views:

300

answers:

1

Supposing these are my parent and my child objects:

Parent:

@Entity
@Table( name = "import_table" )
public class ImportTable { 
    @Cascade( { CascadeType.ALL, CascadeType.DELETE_ORPHAN } )
    @OneToMany(
        mappedBy = "table",
        fetch = FetchType.EAGER
    )
    public List<ImportTableColumn> getColumns()
    {
        return columns;
    }
    ... setter is defined but I don't think it's important for the example
}

Child:

@Entity
@Table( name = "import_table_column" )
public class ImportTableColumn {
    @ManyToOne
    @JoinColumn(
        name = "import_table_name",
        nullable = false
    )
    public ImportTable getTable()
    {
        return table;
    }
}

The following pseudo-code will work

  • Create instance of ImportTable, add 2 columns, create a session, save it, close the session;
  • Read saved instance in a different session, remove one column;
  • Save it in another session;
  • Check number of columns and is equal to one.

But the following won't work:

  • Create instance of ImportTable, add 2 columns, create a session, save it, close the session;
  • Read saved instance in a different session;
  • Recreate saved object manually;
  • Remove the column;
  • Save it in another session;
  • Check number of columns and is equal to one.

The reason for this is that we have a Java server/ Flex client application, and we need to load the object, send it to the client, let the client do whatever it has to do, send the object back to the server, and then save it.

I think Hibernate is getting lost when I recreate the object. As far as I know, Hibernate does inject something in the object when it's retrieved from the database. When I recreate the object, I am not copying anything that is not a declared field in the object class. This is the code to recreate the object (for my unit test):

private ImportTable recreate( ImportTable original ) throws IOException
{
    final ImportTable copy = new ImportTable();
    copy.setDatabaseTableName( original.getDatabaseTableName() );
    copy.setDisplayTableName( original.getDisplayTableName() );
    if( original.getColumns() != null ) {
        copy.setColumns( new ArrayList<ImportTableColumn>( original.getColumns().size() ) );
        for( ImportTableColumn originalColumn : original.getColumns() ) {
            final ImportTableColumn copyColumn = new ImportTableColumn();
            copyColumn.setTable( copy );
            copyColumn.setDatabaseColumnName( originalColumn.getDatabaseColumnName() );
            copyColumn.setDatatype( originalColumn.getDatatype() );
            copyColumn.setExcelColumnName( originalColumn.getExcelColumnName() );
            copyColumn.setId( originalColumn.getId() );
            copyColumn.setLength( originalColumn.getLength() );
            copyColumn.setPk( originalColumn.isPk() );
            copyColumn.setRequired( originalColumn.isRequired() );
            copyColumn.setPrecision( originalColumn.getPrecision() );
            copy.getColumns().add( copyColumn );
        }
    }
    return copy;
}

I believe hibernate is getting lost when I recreate the object. What I want hibernate to do is to compare what is in the database with what is in the object and save the differences only. Is there any way to do that?

+2  A: 

Hibernate wraps collection instances into appropriate subclasses of AbstractPersistentCollection when the owner entity is first attached to session.

That PersistentCollection is then tracking deleted collection elements; without it Hibernate will only be able to perform inserts / updates on them (in most cases; for some id generator classes even that is not possible).

You're basically out of luck there; the only thing you can do is to load an existing entity (ImportTable) from the database and modify it (e.g. delete collection elements that are present in loaded copy but not in your clone) then save it.

That said, I don't quite follow why you need to clone your entity in the first place (I don't know Flex ... are you marshalling your entity to XML / JSON / etc?) All PersistentCollection implementations are Serializable and thus can be sent over the wire and back. There are ways to marshall them to XML and back as well.

ChssPly76
The flex engine (flex.messaging) won't serialize the object, I believe the engine uses reflection to read the field, and then it uses its own serialization engine that is compatible with the flex client. I was just checking the source code, when a list comes back from the client, the engine creates a ArrayList to hold its contents.I guess I will have to implement the solution myself. I may use reflection (thru commons-bean) to read all the object getters, figure out if there are any lists, and then read the database and compare the list ids using the hibernate annotations that are in there.
Ravi Wallau
By reading the @Id annotation. I will evaluate if that case will happen often enough to justify that extra coding, otherwise I may do that manually in the object itself.
Ravi Wallau