Object Relational Mappers: Difference between revisions

From Elvanör's Technical Wiki
Jump to navigation Jump to search
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Java: Hibernate ==
== [[Hibernate|Java: Hibernate ]] ==


* If you specify a one-to-many or many-to-many mapping, be sure to use the same mapping as the Java collection interface. A Set mapping won't work with a List collection, for example.
* Hibernate is THE reference ORM, the most advanced solution available right now. It is extremely powerful although it takes quite some time to fully learn it (especially its model mappings, which can be complex since they allow almost any kind of mapping).
 
* In Hibernate, lazy loading is on by default for collections. This means the collections are fetched from the database only when they are used (never if they are not used). '''Warning:''' if the loading appears when the Hibernate session is already closed, it will '''fail.'''
 
* If you have an object and a many-to-one mapping on this object (such as Item that belongs to a Category), and you happen to have the ID of the Category but not the associated Java object, in order to store the item on the database the fastest way is to create a new virtual Category and call setID(known_id) on this newly created object. Then, once you save the object, the virtual Category will not be saved (updated) as it already exists. For this to happen (eg, for the object not to be overriden), you must use the ID of the Object as the equals() method. '''This is not recommended.''' Note that by default Hibernate distinguishes between objects by using their addresses in memory.
 
* '''Update:''' The previous remark would work, '''but is not the recommended way.''' The correct way is to use session.load(Category.class, category_id) and use a proxy. This means the object won't actually be fetched from the DB, but you'll be able to use it as a Java object. This is nice. By default, a mapping uses a proxy.
 
=== Object Lifecycle ===
 
* To reattach a detached instance to the session, you can use either update(), which will schedule an SQL UPDATE statement when the session is flushed, or merge(). update() will only work if the session does not contains already the object, while merge() will always work regardless of the session state.
** Be careful, as the object may in fact already be loaded via other objects into the session! Thus it's hard to be always sure that your object is not yet in the session.
 
* If you don't want to issue an UPDATE statement, you can use lock(object, LockMode.NONE). In this case, you must be sure however that the detached instance has not been modified.
 
=== Cascade ===
 
* The concept of cascade implies somehow that one object "belongs" to another one. When saving, updating, or deleting the parent object, the child will also be saved, updated or deleted.
 
* Apparently, it is not possible to cascade in the other direction, that is, from the child to the parent. Saving a child when the parent is not yet saved won't persist the parent.
 
=== Collections ===
 
* Never try to associate a collection reference to more than one object. This will cause lots of errors. If you need to, you can copy all the objects from a collection to another one. This applies even if you deleted the object containing the collection reference first.
 
=== Transactions ===
 
* Real database transactions are only possible if the underlying DB supports them. This means that with MySQL MyISAM tables, transactions are very limited. In an Hibernate context, nothing is written to the DB unless the session is flushed. When it is, however, everything is written and cannot be rolled back later.
 
* Bottom-line: use InnoDB if you need transactions (and transactions are almost mandatory when using an ORM I would say).
 
=== Hibernate & EJB3 Annotations ===
 
* The EJB specification indicates whether the property should be accessed by field or by getter method. This depends on where you put the annotation. You should put it before the field if you want field access, and before the getter method to get property access.
 
* The best documentation for Hibernate annotations is the reference Hibernate documentation, but also the javax.persistence API which documents all possible official EJB annotations.
 
* Here is an example of a (Groovy) annotated class:
<pre>
@Entity()
@Table(name="shop_category")
class ShopCategory
{
@Id
Long id
@ManyToOne
ShopCategory parentCategory
String name
@OneToMany(targetEntity = ShopItem.class, mappedBy="category")
Set items
@OneToMany(cascade = [javax.persistence.CascadeType.ALL], targetEntity = ShopCategory.class, mappedBy="parentCategory")
Set subCategories
}
</pre>
 
=== Locking ===
 
* If you get StaleObjectExceptions in your code, this means that you have a concurrency problem. Typically, you access one object in a transaction, try to update it, while in another transaction the same object was already modified. In Grails, since there is a session per request model, this typically means that two HTTP requests were fired at the same time. Thus it is most probably a JavaScript error.
 
* This can also happens if you have a detached instance that you try to reattach, but the SQL data row was deleted in the meantime.

Latest revision as of 10:44, 19 May 2008

Java: Hibernate

  • Hibernate is THE reference ORM, the most advanced solution available right now. It is extremely powerful although it takes quite some time to fully learn it (especially its model mappings, which can be complex since they allow almost any kind of mapping).