0

I'm using PlayFramework 2.3 and i have the following classes:

MyEntity.java:

@Entity(name = "myentity")
public class MyEntity extends Model {
    @Id
    @GeneratedValue
    public long id;

    @OneToOne(cascade = CascadeType.ALL, optional = true)
    @JoinColumn(name = "actual_version_id", nullable = true)
    public Version actualVersion;

    @OneToOne(optional = true)
    @JoinColumn(name = "next_version_id", nullable = true)
    public Version nextVersion;

    ...
}

Version.java

@Entity(name = "version")
public class Version extends Model {
    @Id
    @GeneratedValue
    public long id;

    @OneToOne
    @JoinColumn(name = "entity_id", nullable = false)
    public MyEntity entity;

    ...
}

When i want to make a new version for the entity, i copy it by detach, set the id to 0, and persist like this:

public Version clone(){
    JPA.em().detach(this);
    this.id = 0;
    JPA.em().persist(this);
    return this;
}

If i use the following code it works properly (first code)

    entity.nextVersion = entity.actualVersion.clone();
    JPA.em().flush();
    entity.actualVersion = entity.nextVersion;
    entity.nextVersion = null;
    JPA.em().flush();

I didn't really like this code, because i could use it like this (second code)

    entity.actualVersion = entity.actualVersion.clone();
    JPA.em().flush();

But if I do this the foreign key doesn't update in the 'entity' table and i don't know why. Can anybody tell me what's the difference between the two implementtation of cloning? It seems some JPA black magic for me, but i couldn't find the answer.

EDIT:

This is a refactored code to make it easier to undestand. I'm not overriding any function from the Object class, or any other (my clone() function is called newRound in the original code with 2 parameters for example)

I don't really want to make any model modification like adding CascadeType.ALL to the annotation, or anything like that, because this is a program in production now, and i don't know what bugs would that make.

I just want to know why the first code updates the foreign key in the entity (actual_version_id) and the second doesn't. I think it has to be something with that CascadeType.ALL annotation parameter at the actualVersion variable.

aBnormaLz
  • 809
  • 6
  • 22
  • Have you set cascading object writes during persist? – Tassos Bassoukos Nov 17 '15 at 17:05
  • I don't really understand your question. What do you mean by seting the cascading object writes? – aBnormaLz Nov 17 '15 at 17:12
  • 1
    I'm sure it's JPA provider implementation dependent, but ... I would say that manipulating the key value yourself on an entity whose identity is provider managed (`@GeneratedValue`) is a party foul. – scottb Nov 17 '15 at 17:16
  • @aBnormaLz try `@OneToOne(cascade=CascadeType.ALL)`. – Tassos Bassoukos Nov 17 '15 at 17:18
  • Actually manipulating with ids is not a foul http://stackoverflow.com/questions/11625096/cloning-jpa-entity @Tassos Bassoukos Do you mean to annotate MyEntity attribute with that? I don't know if that makes any other problem in the code (it's a big online project that i'm supporting at the time) – aBnormaLz Nov 17 '15 at 17:22
  • Updating the ID field IS DEFINITELY PROVIDER SPECIFIC, and directly updating fields is also provider specific. Due to bytecode enhancement. – Neil Stockton Nov 18 '15 at 09:20

1 Answers1

0

Be very careful with clone() in a JPA setting; the JPA environment usually adds tracking properties to the bytecode of a class, and might get confused. Instead, override the default clone() to create an actual object and copy over all properties manually, one-by-one.

Tassos Bassoukos
  • 16,017
  • 2
  • 36
  • 40