Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate returns list with null values (OneToMany annotation with List type)

I am experiencing a problem where as Hibernate (4.1.8.FINAL) returns a list with NULL values (unidirectional OneToMany mapping).

What I'm getting: I am getting a List with size of 21 where as EntryAddress is on 10th index, and 2nd Entry Address is on 20th index.

Entry [addresses=[null, null, null, null, null, null, null, null, null, null, EntryAddress [id=5, entryId=3, precedence=10, line=Line 3.1], null, null, null, null, null, null, null, null, null, EntryAddress [id=6, entryId=3, precedence=20, line=Line 3.2]]]

What I expect - I expect a List with only two EntryAddress objects:

Entry [addresses=[EntryAddress [id=5, entryId=3, precedence=10, line=Line 3.1], EntryAddress [id=6, entryId=3, precedence=20, line=Line 3.2]]]

Here's the minimal source code:

@Entity
@Table(name = "entry")
public class Entry {
    ...
    @OneToMany(fetch = FetchType.EAGER, orphanRemoval = true)
    @JoinColumn(name = "entry_id")
    @OrderColumn(name = "precedence")
    private List<EntryAddress> addresses;
    ...
}
@Entity
@Table(name = "entry_address")
public class EntryAddress {
    @Id
    @GeneratedValue
    @Column(name = "id")
    private Integer id;

    @Column(name = "entry_id")
    private Integer entryId;

    @Column(name = "precedence")
    private Integer precedence;
...
}

Here's the mysql structure (engine InnoDB):

CREATE TABLE  entry  (
   id  int(10) unsigned NOT NULL AUTO_INCREMENT,
   name  varchar(500) NOT NULL,
   active  int(1) NOT NULL DEFAULT '0',
   modifiedTS  timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
   createdTS  timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY ( id )
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

CREATE TABLE  entry_address  (
   id  int(10) unsigned NOT NULL AUTO_INCREMENT,
   entry_id  int(10) unsigned NULL,
   precedence  int(2) NULL DEFAULT '0',
   line  varchar(255) DEFAULT NULL,
  PRIMARY KEY ( id ),
  UNIQUE KEY  entry_address_uq  ( entry_id , precedence )
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

When I try to replace "List" with "Set" then collection doesn't have NULL values, but the sequence/precedence is not working.

One interesting point I found is, if I set precedence of 1st EntryAddress to 1, and set precedence of 2nd EntryAddress to 2 then I am getting a List with a size of 2. So it seems the precedence plays a role during returning of List although the precedence should only be used for sorting.

Can you please tell me what I'm doing wrong? Thank you :-)

like image 771
pitschr Avatar asked Nov 09 '12 12:11

pitschr


3 Answers

From the javadocs of OrderColumn: "The order column must be of integral type. The persistence provider maintains a contiguous (non-sparse) ordering of the values of the order column when updating the association or element collection. The order column value for the first element is 0."

So, the expectation is that the values of the OrderColumn start from 0 and are continuous values. So, when the values are not continous Hibernate adds null elements to your Java list.

I think this behavior of OrderColumn is similar to list-index behavior in hibernate xml mapping.

like image 62
Sathish Kumar Avatar answered Nov 02 '22 06:11

Sathish Kumar


The problem is the difference between List and Set.

I am getting a List with size of 21 where as EntryAddress is on 10th index, and 2nd Entry Address is on 20th index.

This is pretty musch a Set where it was supposed to be List!

When you "replace List with Set", did you remember to remove the @OrderColumn(name = "precedence")? because if your using Set, you can't have an Order column.

like image 43
AmirMV Avatar answered Nov 02 '22 08:11

AmirMV


I found the solution, I used it and this solved the issue

@OneToMany(orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
@JoinColumn(name = "entry_id")
@OrderBy("precedence")
private List<EntryAddress> addresses;

@OneToMany(orphanRemoval = true)
@LazyCollection(LazyCollectionOption.FALSE)
@JoinColumn(name = "entry_id")
@OrderBy("precedence")
private List<EntryContact> contacts;
like image 25
pitschr Avatar answered Nov 02 '22 06:11

pitschr