"Hibernate" Parent-child relationship

Source: Internet
Author: User
Tags addchild flush

Transferred from http://www.xfbbs.com/Book/database/Hibernate/example-parentchild.html

Most people who have just come into contact with hibernate start with the modeling of a parent-child relationship (Parent/child type relationship). There are two ways to model a parent-child relationship. For a variety of reasons, the easiest way to do this is to model both parent and child as entity classes and create a <one-to-many> association from parent to child, especially for beginners. Another way is to declare a child as a <composite-element> (composition element). In fact, the default semantics associated with one to many in hibernate are far from the usual semantics of composite element close to the parent/child relationship. Here's how to build an effective, graceful parent/child relationship using a cascading bidirectional One-to-many Association (bidirectional one to many association with Cascades). It's not difficult at all. 22.1. A point to note about the collections

The Hibernate collections is treated as a logical part of the entity to which it belongs rather than the entity it contains. This is very important. It is mainly embodied in the following points:

When you delete or increase an object in collection, the version value of the collection owner is incremented.

If an object removed from the collection is an instance of a value type, such as the composite element, then the persisted state of the object is terminated and its corresponding record in the database is deleted. Similarly, adding an instance of the value type to collection will cause it to be persisted immediately.

On the other hand, if you remove an entity from the collection of a One-to-many or Many-to-many association, the object is not deleted by default. This behavior is perfectly logical-changing the internal state of an entity should not cause the entity associated with it to disappear. Similarly, adding an entity to the collection does not make it persistent.

In fact, the default action to add an entity to the collection is simply to create a connection between two entities, and delete the connection only when it is removed. This kind of treatment is appropriate for all situations. It is completely unsuitable for a parent-child relationship, in which the existence of child objects is bound to the lifetime of the parent object. 22.2. Bi-directional one-to-many relationship (bidirectional one-to-many)

Let's say we want to implement a simple <one-to-many> association from parent to child.

<set name= "Children" >
    <key column= "parent_id"/> <one-to-many class=
    "Child"/>
</ Set>

If we run the following code

Parent p = ...;
Child C = new Child ();
P.getchildren (). Add (c);
Session.save (c);
Session.flush ();

Hibernate generates two SQL statements:

An INSERT statement that creates a record for C

An UPDATE statement that creates a connection from P to C

This is not only inefficient, but also violates the limit of the column parent_id Non-empty. We can resolve a problem that violates a non-empty constraint by specifying not-null= "true" on the Collection class map:

<set name= "Children" >
    <key column= "parent_id" not-null= "true"/> <one-to-many
    "Child"/ >
</set>

However, this is not a recommended solution.

The root cause of this phenomenon is that the connection from P to C (foreign key parent_id) is not part of the state of the child object and is therefore not created in the INSERT statement. So the solution is to add this connection to the child's mapping.

<many-to-one name= "Parent" column= "parent_id" not-null= "true"/>

(We also need to add the parent attribute for the class child)

Now that the entity child is managing the state of the connection, we use the inverse property to make collection not update the connection.

<set name= "Children" inverse= "true" > <key column= "parent_id"/> <one-to-many class=
    "Child"/ >
</set>

The following code is used to add a new child

Parent P = (parent) session.load (Parent.class, PID);
Child C = new Child ();
C.setparent (p);
P.getchildren (). Add (c);
Session.save (c);
Session.flush ();

Now, only one INSERT statement is executed.

To get things organized, you can add a Addchild () method to the parent.

public void AddChild ("Child C") {
    c.setparent (this);
    Children.add (c);
}

Now, the code to add a child is this

Parent P = (parent) session.load (Parent.class, PID);
Child C = new Child ();
P.addchild (c);
Session.save (c);
Session.flush ();
22.3. Cascading life cycle (cascading lifecycle)

The need to explicitly call Save () is still cumbersome, and we can use cascading to solve the problem.

<set name= "Children" inverse= "true" cascade= "All" >
    <key column= "parent_id"/>
    class= "Child"/>
</set>

So the code above can be simplified to:

Parent P = (parent) session.load (Parent.class, PID);
Child C = new Child ();
P.addchild (c);
Session.flush ();

Similarly, when you save or delete a parent object, you do not need to traverse its child objects. The following code deletes the database records corresponding to the object P and all its child objects.

Parent P = (parent) session.load (Parent.class, PID);
Session.delete (p);
Session.flush ();

However, this piece of code

Parent P = (parent) session.load (Parent.class, PID);
Child C = (child) P.getchildren (). iterator (). Next ();
P.getchildren (). Remove (c);
C.setparent (null);
Session.flush ();

C will not be deleted from the database; it will only delete the connection to P (and will result in a violation of the NOT NULL constraint, in this case). You need to explicitly call Delete () to delete the child.

Parent P = (parent) session.load (Parent.class, PID);
Child C = (child) P.getchildren (). iterator (). Next ();
P.getchildren (). Remove (c);
Session.delete (c);
Session.flush ();

In our case, if there is no parent object, the child object should not exist, and if the child object is removed from the collection, we actually want to delete it. To achieve this requirement, you must use the Cascade= "All-delete-orphan".

<set name= "Children" inverse= "true" cascade= "All-delete-orphan" >
    <key column= "parent_id"/>
    <one-to-many class= "Child"/>
</set>

Note: Even if inverse= "true" is specified in the mapping of the collection side, cascading is still handled by traversing the elements in the collection. If you want to insert, delete, update the child object by cascading, you must add it to the collection, and only call SetParent () is not enough. 22.4. Cascading and unsaved values (Cascades and Unsaved-value)

Let's say we loaded a parent object from the session, the user interface modifies it, and then we want to call Update () in a new session to save the changes. Object parent contains a collection of child objects, and because cascading updates are turned on, hibernate needs to know which children objects are newly instantiated and which represent records that already exist in the database. We assume that the identity attributes of both parent and child objects are automatically generated, and the type is Java.lang.Long. Hibernate uses the value of the identity attribute, and the version or timestamp property, to determine which child objects are new. (See section 11.7, "Automatic state detection.") In Hibernate3, the explicit designation of Unsaved-value is no longer necessary.

The following code updates the parent and child objects and inserts the Newchild object.

Parent and child were both loaded in a previous sessions
parent.addchild (child);
Child newchild = new Child ();
Parent.addchild (newchild);
Session.update (parent);
Session.flush ();

So, that's all very. The case of a generated identifier, but what about assigned identifiers and composite ident Ifiers? This is more difficult, since Hibernate can ' t with the identifier property to distinguish between a newly instantiated CT (with an identifier assigned by the user) and an object loaded in a previous session. In this case, Hibernate would either use the timestamp or version, or would actually query the Second-level cache O R, worst case, the database, to the if the row exists.

This is good for automatically generating identities, but what about self-allocating identities and composite identities? This is a bit of a hassle because hibernate there is no way to distinguish between newly instantiated objects (identity specified by the user) and the objects that were mounted in the previous session. In this case, hibernate will use the timestamp or version attribute, or query the second level cache, or, in the worst case, query the database to see if the row exists. 22.5. Conclusion

There are a lot of things that need to be done, and it may be confusing for beginners. But in practice they all work very well. The parent-child object pattern is frequently used by most hibernate applications.

In the first paragraph we mentioned another option. None of these problems appear in the <composite-element> map, which accurately conveys the semantics of the parent-child relationship. Unfortunately, there are two major limitations of composite elements: Composite elements cannot have collections, and they cannot be child objects of any other entity except for the unique parent object.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.