jd001982 wrote:
Roughly scanned your web site and have a question -- with mappings like the following:
...
aren't you just writing SQL statements in XML format? Why not just write your data access code using plain JDBC?
Plain JDBC is unsafe (always possible to miss leaks) and awkward. Wrapping JDBC with lychee is
1) Safer. No cursor leaks since all JDBC queries executed by a single class throughout the whole system. No statement leaks since all JDBC queries executed by a single class throughout the whole system. No column references by number, compile-time checking instead.
1) Simpler.
2) Less code (=> cleaner code => better code). Code is at least half as much as the JDBC variant.
But what's most important - it
let's you be flexible about how you think about things. Having this join class defined you can now think of it as of an 'entity' and define relationships to other entities within it:
Code:
<class name="LineItemJoinTradeableJoinProduct">
<statement name="default">
<from>
<![CDATA[
from
LineItem, Tradeable, Product, VatRate, SpikeControl,
SupplierItem,
BuyingCycle startBuyingCycle,
BuyingCycle endBuyingCycle
]]>
</from>
<where>
<![CDATA[
where
LineItem.tradeableId = Tradeable.id AND
Tradeable.productId = Product.id AND
Product.vatCode = VatRate.code AND
LineItem.id = SpikeControl.lineItemId AND
SpikeControl.buyingCycleId = :cycleId AND
LineItem.prefSupplierItemId = SupplierItem.id AND
-- limit by cycle
startBuyingCycle.id = LineItem.liveCycleId AND
endBuyingCycle.id (+) = LineItem.deadCycleId AND
trunc(startBuyingCycle.intendedStartDate) <=
trunc(:cycleDate) AND
( (trunc(:cycleDate) <
trunc(endBuyingCycle.intendedStartDate)) OR
(LineItem.deadCycleId is null) )
]]>
</where>
</statement>
<field name="id" column="LineItem.id" type="Long" isId="true"/>
<field name="price" column="LineItem.price" type="BigDecimal"/>
<field name="rrp" column="LineItem.rrp" type="BigDecimal"/>
<field name="isVisible" column="LineItem.visible"
type="boolean_Y_N"/>
<field name="sku" column="Tradeable.sku" type="String"/>
<field name="tradeableEanCode" column="Tradeable.eanCode"
type="String"/>
<field name="productTypeId" column="Product.productTypeId"
type="Long"/>
<field name="name" column="Product.name" type="String"/>
<field name="itemSize" column="Product.itemSize" type="String"/>
<field name="vatRate" column="VatRate.rate" type="BigDecimal"/>
<field name="vatCode" column="VatRate.code" type="Character"/>
<field name="isUnderSpike" column="SpikeControl.underSpike"
type="boolean_Y_N"/>
<field name="forecastQuantity"
column="SpikeControl.forecastQuantity" type="Long"/>
<relation name="productType" type="one_child"
other-class="ProductType" this-field="productTypeId" other-field="id"/>
<relation name="vatRate" type="one_child"
other-class="VatRate" this-field="vatCode" other-field="code"/>
<relation name="preferredSupplierItem" type="one_child"
other-class="SupplierItem" this-field="preferredSupplierItemId" other-field="id"/>
<relation name="categories" type="many_via_link"
other-class="Category" this-field="id" other-field="id"
link-class="LineItemCategory" link-this-field="lineItemId" link-other-field="categoryId"/>
</class>
So you've got the same tool to use both for 'traditional' O/R mapping (Lychee got relationships mechanism for that, you can traverse object graph (database) as well) and for unrestricted native SQL.
Apparently the mechanism allows to vary the fields at run-time, this is a minor advantage though:
Code:
mapper.loadAll("*", LineItemJoinTradeableJoinProduct.class)
mapper.loadAll("id, price, rrp", LineItemJoinTradeableJoinProduct.class)
Now imagine you come to a project with loads (~1000) queries like this and even more complex. What would you do? JDBC - nah, no good (explained earlier), Hibernate - won't do it. Lychee will do it safely and tidily.
Note that you can define many statements within one class.
All of these features form a very flexible base which
combines the power of joins and native SQL with traditional O/R mapper features like relationships traversing.
Regards,
Vitaly