habs jetzt für meine Schulung gezeigt.
I. klassisches JDBC
private List<Stockdescr> allStockdescr() {
List<Stockdescr> res = new ArrayList<Stockdescr>();
Statement stmt;
String strStmt = "SELECT * FROM STOCK_DESCR";
try {
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(strStmt);
while (rs.next()) {
Stockdescr stockdescr = new Stockdescr();
stockdescr.setId(rs.getInt("id"));
stockdescr.setName(rs.getString("name"));
stockdescr.setPrice(rs.getBigDecimal("price"));
res.add(stockdescr);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
logger.error("Problems with statement: " + strStmt, e);
closeCon();
}
return res;
}
und
private void connect() {
Properties props = loadProperties("jdbc.properties");
try {
Class.forName(props.getProperty("db.driverClass"));
} catch (ClassNotFoundException e) {
logger.error("Driver not found", e);
}
try {
con = DriverManager.getConnection(props.getProperty("db.jdbcUrl"),
props.getProperty("db.user"), props.getProperty("db.pwd"));
} catch (SQLException e) {
// TODO Auto-generated catch block
logger.error("No Connection", e);
System.exit(0);
}
}
und
private void closeCon() {
if (con!= null) {
try {
con.close();
} catch (SQLException e) {
// EINER DER W.E.N.I.G.E.N FÄLLE, in denen ein leerer Exception block ok ist!!!!!
}
}
}
Zum Vergleich
und jetzt mit ibatis in spring für quasi das gleiche (alle Werte der STOCK_DESCR Tabelle laden).
public List<Stockposition> loadAll() {
return getSqlMapClientTemplate().queryForList("allStockposition");
}
gut. man muss ein paar xml-config Dateien schreiben, wo unter anderem der sql code ausgelagert ist und damit auch besser separiert ist. Das ist sehr copy und paste und für neue SQL Statements gegen die gleiche Tabelle muss man nur 1 neues xml Element schreiben, für eine weitere Tabelle genau 1 weiteres xml Element.
ibatis:
<sql id="select-stockdescr">
select
ID,
NAME,
PRICE
from STOCK_DESCR
</sql>
<select id="allStockdescr" resultClass="stockdescr">
<include refid="select-stockdescr"/>
ORDER BY ID
</select>
spring:
<bean id="stockdescrDao"
class="de.spintegration.fussi.dao.ibatis.StockdescrDaoImpl">
<property name="sqlMapClient" ref="sqlMapClient" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driverClass}"/>
<property name="url" value="${db.jdbcUrl}"/>
<property name="username" value="${db.user}"/>
<property name="password" value="${db.pwd}"/>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:jdbc.properties"/>
</bean>
<bean id="sqlMapClientTemplate"
class="org.springframework.orm.ibatis.SqlMapClientTemplate">
<property name="sqlMapClient" ref="sqlMapClient" />
</bean>
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="sql-map-config.xml"/>
</bean>
Aber das ist es fast schon. Und das ist nur ein Teilaspekt der Vorteile.
;D
Das hört sich ein bischen nach where Klauseln an. Also das kann HSQL.
Hab bestimmt 8 Monate nichts mehr mit Hibernate gemacht, aber ein Punkt auf den eigentlich alle stossen ist der n+1 select Klassiker. Und den kann man mit outer joins umschiffen. Hibernate ist nicht dafür da, um sich SQL zu sparen.
Speaking of... ;D
Hier sind alle SQL Experten auf SAS Schulung im Urlaub oder ihnen werden Kinder geboren.
Zu meinem Problem:
SELECT PE.MONEY - Sum(OD.PRICE * OD.AMOUNT)
FROM
PERSON PE, ORDERS OD
WHERE
OD.ID_TRADER = PE.ID
AND
PE.ID = #id#
Das ist ein join mit der Tabelle Person und der Tabelle Orders über PE.ID - ORDERS_ID_TRADER.
Manchmal gibt es aber zu der Person keine ORDERS, heisst SUM(OD.PRICE * OD.AMOUNT) ergibt null. Dummerweise ergibt dann er gesamte Ausdruck NULL, obwohl PE.Moner nicht NULL ist?
Du erwartest von den OR-Mappern eine Art Round-Trip Engineering für Model Driven Architecture. Ist es nicht eher die Idee von MDA, dass man von den Implementierungs-unabhängigen Modellen herunterarbeitet? Was ich so von MDA-Leuten gehört habe ist eher, dass die ziemlich round-trip engineering kritisch sind. Abgesehen ist Modell generieren schon gut. Spring IDE macht das jetzt ganz schön für Bean Container.
Wer Fowlers "Patterns of Enterprise Application Architecture" gelesen hat, wird die ersten "2,5" davon wiedererkennen (Mal so aus dem Gedächtnis hingeschrieben):
- Single-Table-Inheritance: Alle Klassen einer Hierarchie in eine Tabelle
- Class-Table-Inheritance
- Concrete-Class-Table-Inheritance: Je konkrete Klasse eine Tabelle, Attribute der Oberklassen werden "ausmultipliziert"
- One-Table-Per-Class: Eine Tabelle je Klasse, Vererbungsbeziehung per Fremdschlüssel(also Delegation auf Tabellenebene)
- Meta-Modell: Abbildung der Klassenstruktur in ein Meta-Modell mit Tabellen für Typen, Assoziationen, Vererbung, Objekte, Verknüpfungen und Werte (für "primitive" Typen wie Strings)
Solch ein Mapper ist mir bisher halt nicht bekannt... Kann man sich aber selbst schreiben... ;) Ansonsten können wir das bei einem Bier diskutieren, wenn du mal in Hannover bist... ;D
Aber man kann die alle mit Hibernate implementieren. Hat aber natürlich nicht den Namen des Patterns in dem Hibernate-Metadata.
http://www.hibernate.org/hib_docs/reference/en/html/inheritance.html
Mit Hibernate spart man sich auch nicht wirklich SQL, unser Ansatz war halt, da wir eben erstmal isoliert entwickeln wollten, dass man dieses Verhalten tief in die Datenbank schiebt. Wahrscheinlich sind Views auch nicht der Weisheit letzter Schluss, vielleicht wären StoredProcedures sogar noch eine bessere Wahl. Aber in letzterem Fall hätten wir eben recht viel an anderen Stellen verändern müssen, was so noch nicht gewünscht war.
Verschiebt ihr nicht mit beiden Lösungen die Implementierung auf eine low-level Ebene. Man kann das wie gesagt auch im Hibernate Modell definieren. Ich hab z.B. auch ein Single-Table-Inheritance: Alle Klassen einer Hierarchie in eine Tabelle in meinem IBatis Modell.
<resultMap id="person" class="de.spintegration.fussi.bo.Person">
<result property="id" column="ID"/>
<result property="name" column="NAME"/>
<result property="pwd" column="PWD"/>
<result property="email" column="EMAIL"/>
<discriminator column="TYPE" javaType="String">
<subMap value="Trader" resultMap="trader"/>
<subMap value="Admin" resultMap="admin"/>
</discriminator>
</resultMap>
<resultMap id="trader" class="de.spintegration.fussi.bo.Trader" extends="person">
<result property="money" column="MONEY"/>
</resultMap>
<resultMap id="admin" class="de.spintegration.fussi.bo.Admin" extends="person">
</resultMap>
wobei im Objekt-Modell Trader extends Person und Admin extends Person ;)
Ansonsten können wir das bei einem Bier diskutieren, wenn du mal in Hannover bist...
Gerne. Nur bin ich da praktisch nie. Freunde von mir bezeichnen meinten schon, ich wär sowas wie die Luxusausführung eines chinesischen Wanderarbeiters.