| I have the following class:
@Audited @DynamicInsert @DynamicUpdate
@Entity(name = "ResourcePool")
@Proxy(proxyClass = ResourcePool.class)
@Table(
name = "ec_resource_pool",
uniqueConstraints =
@UniqueConstraint(
name = "iu_resource_pool_name",
columnNames = "name"
)
)
public class ResourcePoolImpl
extends AbstractProtectedPropertySheetOwner
implements ResourcePool
{
...
private UUID m_id;
private SortedSet<String> m_resourceNames;
...
@Override public boolean addResourceName(
@NonNls @NotNull String resourceName)
{
if (m_resourceNames == null) {
m_resourceNames = CollectionUtil.createCaseInsensitiveSet();
}
return m_resourceNames.add(resourceName);
}
...
@Column(
length = UUID_LENGTH,
updatable = false,
nullable = false
)
@DocumentId
@GeneratedValue(generator = "ecid")
@GenericGenerator(
name = "ecid",
strategy = "com.electriccloud.dao.EntityIdentifierGenerator"
)
@Id @NonNls @NotNull @Override public UUID getId()
{
return m_id;
}
...
@AuditJoinTable(name = "ec_resource_pool_resource_aud")
@Column(
name = "resource_name",
length = MAX_NAME_LENGTH
)
@ElementCollection(fetch = LAZY)
@JoinTable(
name = "ec_resource_pool_resource",
joinColumns =
@JoinColumn(
name = "resource_pool_id",
foreignKey = @ForeignKey(name = "fk_resource_pool")
)
)
@Nullable @Override
@SortComparator(CaseInsensitiveOrdering.class)
public SortedSet<String> getResourceNames()
{
return m_resourceNames;
}
...
@Override public boolean removeResourceName(
@NonNls @NotNull String resourceName)
{
return m_resourceNames != null && m_resourceNames.remove(resourceName);
}
...
@Override public void setId(@NonNls @Nullable UUID id)
{
m_id = id;
}
...
@Override public void setResourceNames(SortedSet<String> resourceNames)
{
m_resourceNames = resourceNames;
}
}
The join table ec_resource_pool_resource and the audit table ec_resource_pool_resource_aud both have case-insensitive collation order. I create a resource pool whose m_resourceNames with some id which contains the entry 'foo', which produces a row in ec_resource_pool_resource with that id and resource_name = 'foo' I then do: resourcePool.remove("foo"); resourcePool.add("FOO"); // Differs from the previous value only by case Once this is committed, I find I have TWO rows in ec_resource_pool_resource with the same id one with resource_name = 'FOO' (as expected) but the original one with resource_name = 'foo' – which should have been deleted, but was not. (NOTE – If you have auditing turned on, you won't be able to get this far, due to a constraint violation issue which I will file a separate JIRA for.) If I make further changes only by case (e.g. tothe resource 'Foo'), then I get even more duplicated rows in ec_resource_pool_resource. This problem does NOT occur if I put a flush between the delete and the add. This problem has existed at least since Hibernate 4.3.x. I haven't yet turned this into a test case – hopefully I'll be able to do so fairly soon. |