6

I am sending an object from UI. This object is going to be created with a reference to an existing child.

This is simple illustration for this relation.

class ParentEntity {
    @Id
    Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    private ChildEntity child;
}

class ChildEntity {
    @Id
    Long id;
}



ChildEntity child = new ChildEntity();
child.setId(1);
//parentEntity is created based on data sent from UI
parentEntity.setChild(child);

When I save this object, Hibernate gives me " org.hibernate.TransientPropertyValueException: object references an unsaved transient instance ".

I don't have to save a child as I do not change child at all. Just need to save child's id in parent's table.

I've tried to use few CascadeType, but none of them worked.

Chris
  • 199
  • 2
  • 13
  • I also don't want to select the child from db and set to parent ,just to save without error. If I have to, I will. but.... – Chris Aug 21 '15 at 00:58

2 Answers2

9

Just use the proxy for the child:

parentEntity.setChild(entityManager.getReference(ChildEntity.class, childId));

The point here is to use EntityManager.getReference:

Get an instance, whose state may be lazily fetched.

Hibernate will create the proxy containing only the id without going to the database.

Community
  • 1
  • 1
Dragan Bozanovic
  • 23,102
  • 5
  • 43
  • 110
  • Thanks. This solution works but it still selects the child entity from database. I can see hibernate select log when it persists the parent. Is it expected behaviour? – Chris Aug 25 '15 at 08:32
  • No, it should not be loaded. Have you explicitly disabled proxies for `ChildEntity` (`@Proxy(lazy = false)`)? If not, could you explicitly enable it (annotate the entity with `@Proxy`) and try again? – Dragan Bozanovic Aug 25 '15 at 09:52
  • Or, is `ChildEntity` class `final`? – Dragan Bozanovic Aug 25 '15 at 10:32
  • Ok this was perfect working solution. Using getReference(), it does not retrieve child to save the parent. The reason of my issue was that my application flushes the entity after persisting and pulls out the child entity from the parent to return updated data to UI. At this time, that was retrieved. Sorry for my confusion. Anyway, I need a workaround for my situation. – Chris Aug 26 '15 at 00:08
4

You have to decide how do you want to persist ChildEntity with ParentEntity.

  1. If you always want to persist child only by id then you can do like this and FK will block you if its invalid child.

    class ParentEntity {
        @Id
        Long id;
    
        //To directly load/insert/update childId only
        @Column("child_id")
        private Long childId;
    
       // To load the child entity with parent, Note that insertable/updatable MUST be false
       // as we are inserting/updating = true by default on childId column mapping
       @ManyToOne(fetch = FetchType.LAZY)
       @JoinColumn(name = "child_id", insertable = false, updatable = false)
       private ChildEntity child;
    }
    parentEntity.setChildId(childId);
    
  2. But if you want to persist child using your existing model where child is mapped as an object, then you have to fetch the child and set it. parentEntity.setChild(childRepository.findOne(childId)); or you can also write a custom DAO method for getOrCreateChild which can create a new child or find existing one and return it so that you can persist child first.

In your case when you use new keyword for creating childEntity, hibernate will always consider it as detached and tries to persist.

Anudeep Gade
  • 1,365
  • 1
  • 9
  • 18
  • I didn't try this yet but I think it will work. However, with this solution, I shouldn't be getting the child when I retrieve parent. – Chris Aug 25 '15 at 08:35
  • Updated answer with comments, you can still load child with parent but you have to decide that you will not insert/update the child via object as you decided that insert/update via childId only.. – Anudeep Gade Aug 25 '15 at 09:38
  • If you want to save child both by object and id, then you need a custom interceptor by annotating your setters which can load and set the object if id is set and viceversa - set the id if object is set. – Anudeep Gade Aug 25 '15 at 09:47