Hello, I've been experiencing an interesting issue in my application relating to removing an entity from a collection where there is a ManyToAny mapping from the entity that contains the collection to the interface that defines the members in the collection.
Consider the following mapping from the class "Group" for a set of "GroupMember"s:
Code:
public class Group {
...
@ManyToAny(metaDef = GroupMember.TYPE_NAME, metaColumn = @Column(name = "member_type"), fetch = FetchType.LAZY)
@JoinTable(name = "GroupMembership",
joinColumns = @JoinColumn(name = "group_id"),
inverseJoinColumns = @JoinColumn(name = "member_id")
)
private Set<GroupMember> members;
...
}
The AnyMetaDef for the mapping is defined separately:
Code:
@AnyMetaDef(
name = GroupMember.TYPE_NAME,
idType = "long",
metaType = "string",
metaValues = {
@MetaValue(value = SomeType1.TYPE_NAME, targetEntity = SomeType1.class),
...
}
)
There is also a GroupMembership table that looks like this:
Code:
CREATE TABLE GroupMembership (
group_id bigint NOT NULL,
member_id bigint NOT NULL,
member_type varchar(128) NOT NULL,
CONSTRAINT GroupMembership_PK PRIMARY KEY (group_id, member_id, member_type)
);
group_id is foreign key'ed to the Group table and member_id is foreign key'ed to a GroupMember table.
If multiple items (GroupMembers) are added to the "members" set in "Group," and then one is removed, the following error is encountered:
[org.hibernate.SQL] delete from GroupMembership where group_id=? and member_id=?
[o.h.type.descriptor.sql.BasicBinder] binding parameter [1] as [BIGINT] - 15
[o.h.type.descriptor.sql.BasicBinder] binding parameter [3] as [BIGINT] - 20
[o.h.util.JDBCExceptionReporter] Parameter index out of range (3 > number of parameters, which is 2).[o.h.e.d.AbstractFlushingEventListener] Could not synchronize database state with session
org.hibernate.exception.GenericJDBCException: could not delete collection rows: [some.package.name.Group.members#15]
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:140) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:128) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.persister.collection.AbstractCollectionPersister.deleteRows(AbstractCollectionPersister.java:1352) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.action.CollectionUpdateAction.execute(CollectionUpdateAction.java:84) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:187) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) ~[hibernate-core.jar:3.6.0.Final]
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) [hibernate-core.jar:3.6.0.Final]
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) [hibernate-core.jar:3.6.0.Final]
at sun.reflect.GeneratedMethodAccessor79.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_21]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_21]
It seems that the correct delete sql is generated: delete from GroupMembership where group_id=? and member_id=?
However, the binding does not appear to be functioning properly. Tracing through the hibernate code, I noticed in AbstractCollectionPersister.deleteRows() that initially the key ("group_id" in this case) is written to the prepared statement for the deletion in writeKey(). Subsequently, the location of the next parameter to write to the prepared statement is incremented, which is correct. Next, Hibernate goes to write the member_id element to the prepared statement in writeElementToWhere(). Interestingly, the counter is incremented again before the element is written to the prepared statement, thus causing the error.
Does anyone see any issues with what I am doing or does this seem to be a bug in Hibernate? I feel that if my mapping is invalid, then Hibernate should detect the invalid state instead of trying to create an invalid prepared statement.