Hibernate, automatically persist dependant objects
You have to look at cascading operations; this type of operation permits you to manage lifecycle of inner object respect their parent.
@ManyToOne(cascade) if you use Session.persist()
operation or org.hibernate.annotations.@Cascade
if you use not JPA function Session.saveOrUpdate()
.
This is just an example, for full doc point here
For your code, if you want to automatically save Manufacturer
when saving Project
use:
@ManyToOne (fetch = FetchType.EAGER, cascade = {javax.persistence.CascadeType.PERSIST})
@JoinColumn (name = "mfr_id")
public Manufacturer getManufacturer () {
return this.manufacturer;
}
or
@Cascade(CascadeType.PERSIST)
Related videos on Youtube
GordonM
I'm a professional PHP programmer with almost a decade of professional experience and considerably more as a hobbyist programmer. I've also had some exposure to Java, Object Pascal and am interested in learning objective C I've started work on a PHP framework, though it's still at a very early stage and not yet really useful. The current source is available on GitHub. I've also begun development of a CSS3 elastic grid for use on my own projects and had published that on GitHub as well.
Updated on June 04, 2022Comments
-
GordonM over 1 year
I'm quite new to Hibernate and have been trying to determine what it will do for you and what it requires you to do.
A big one is dealing with an object that has dependants that don't yet exist in the database. For example, I have a Project object that includes a Manufacturer field that accepts a Manufacturer object as its value. In the database I have a products table with a mfr_id column that's a reference to the manufacturers table (a fairly typical unidirectional one-to-many relationship).
If the manufacturer assigned to the product object relates to one that's already in the database then there's no problem. However, when I try to save or update an object that references a manufacturer that hasn't been persisted yet, the operation fails with an exception.
Exception in thread "Application" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
I can of course manually check the state of the product's manufacturer by seeing if it's ID field is null and saving it if it is, but this seems like a cumbersome solution. Does Hibernate support automatically persisting dependants if the dependant in question isn't yet persisted? If so, how do I enable that behaviour? I'm using the version of Hibernate bundled with Netbeans (3.5, I believe) and inline annotations for specifying the mapping behaviour. Below are my product and manufacturer classes, cut down to the parts that handle the dependency. (Product extends Sellable which maps to a sellable table, using JOINED as the inheritance strategy It's that table that contains the primary key that identifies the product)
@Entity @Table ( name="products", schema="sellable" ) public abstract class Product extends Sellable { private Manufacturer manufacturer; @ManyToOne (fetch = FetchType.EAGER) @JoinColumn (name = "mfr_id") public Manufacturer getManufacturer () { return this.manufacturer; } /** * * @param manufacturer */ public Product setManufacturer (Manufacturer manufacturer) { this.manufacturer = manufacturer; return this; } }
The dependant Manufacturer
@Entity @Table ( name="manufacturers", schema="sellable", uniqueConstraints = @UniqueConstraint(columnNames="mfr_name") ) public class Manufacturer implements Serializable { private Integer mfrId = null; private String mfrName = null; @Id @SequenceGenerator (name = "manufacturers_mfr_id_seq", sequenceName = "sellable.manufacturers_mfr_id_seq", allocationSize = 1) @GeneratedValue (strategy = GenerationType.SEQUENCE, generator = "manufacturers_mfr_id_seq") @Column (name="mfr_id", unique=true, nullable=false) public Integer getMfrId () { return mfrId; } private Manufacturer setMfrId (Integer mfrId) { this.mfrId = mfrId; return this; } @Column(name="mfr_name", unique=true, nullable=false, length=127) public String getMfrName () { return mfrName; } public Manufacturer setMfrName (String mfrName) { this.mfrName = mfrName; return this; } }
UPDATE: I tried the following from this question, but I still get the transient object exception.
@ManyToOne (fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
I also checked what version of Hibernate is bundled with Netbeans, it's 3.2.5
UPDATE 2: I found that the following appears to apparently work as I wanted.
@ManyToOne (fetch = FetchType.EAGER, cascade = CascadeType.ALL)
However, I suspect that this is not the cascade type I really want. If I delete a product, I don't think deleting its associated manufacturer is the correct action, which is what I believe will happen now.
I did try creating a cascade type that consisted of all the types that were available, but that didn't work either. I got the same exception when I tried to save a product that had an unsaved manufacturer associated with it.
@ManyToOne (fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
I've seen CascadeType.SAVE_UPDATE mentioned in several places, but that mode doesn't seem to be available in the version of Hibernate that comes with Netbeans.
-
GordonM about 10 yearsI tried your suggestion, but I still get the same exception about transient objects when I try to save the object. I also tried the approach suggested in stackoverflow.com/questions/9032998/… of @ManyToOne (fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) but that didn't work either
-
Luca Basso Ricci about 10 yearsare you using saveOrUpdate()? in this case you need
org.hibernate.annotation.@Cascade(CascadeType.SAVE_UPDATE)
-
GordonM about 10 yearsAt the moment I'm just using save(). I'll look at other options when I get home tonight.
-
GordonM about 10 yearsSAVE_UPDATE doesn't seem to be a valid cascade type in the version of Hibernate that came with Netbeans. The hint lists the available options as ALL, PERSIST, MERGE, REFRESH or REMOVE
-
Luca Basso Ricci about 10 yearsYou are using javax.persistence.CascadeType; you have to use org.hibernate.annotation.CascadeType with org.hibernate.annotation.@Cascade annotation
-
GordonM about 10 yearsActually it's annotations, plural. :) Giving it a try now.
-
GordonM about 10 yearsThe @cascade method works as I was expecting. I guess I was just having some confusion regarding persistence annotations versus hibernates annotations. I'm still pretty new to Hibernate and it's taking a while to figure it out. Thanks for the help
-
Luca Basso Ricci about 10 yearsIs preferable to use standard annotations and use Hibernate' specifics only when standard does not cover your requirements