-
Notifications
You must be signed in to change notification settings - Fork 32
Open
Description
I've encountered a strange issue when a unique constraints is spanning multiple columns.
After violating the constraint once, subsequent attempts to persist entities that does NOT violate the constraint are also failing. Test code to replicate the issue below. I was expecting the entire test to succeed, but the last commit is failing. I suspect a bug.
UniqueTest.java
package org.batoo.jpa.core.test.foobz;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.SQLException;
import java.util.Set;
import javax.persistence.Query;
import javax.sql.DataSource;
import junit.framework.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.batoo.jpa.core.test.BaseCoreTest;
/**
* @author sirf
*/
public class UniqueTest extends BaseCoreTest {
@Test
public void testUnique() throws Exception {
DataSource dataSource = this.em().unwrap(DataSource.class);
Connection c = dataSource.getConnection();
execute(c, "CREATE SEQUENCE FooBz_pkFooBz_seq");
execute(c, "CREATE TABLE FooBz (" +
"pkFooBz BIGINT NOT NULL DEFAULT nextval('FooBz_pkFooBz_seq')," +
"fkParent BIGINT NOT NULL DEFAULT currval('FooBz_pkFooBz_seq')," +
"fbname TEXT NOT NULL, PRIMARY KEY (pkFooBz)," +
"UNIQUE (fkParent, fbname))");
execute(c, "ALTER TABLE FooBz ADD FOREIGN KEY (fkParent) REFERENCES FooBz (pkFooBz)");
execute(c, "INSERT INTO FooBz (fbname) VALUES ('000000')");
execute(c, "INSERT INTO FooBz (fbname) VALUES ('000001')");
c.close();
c = null;
dataSource = null;
this.close();
FooBz root0 = this.getFooBz("000000");
FooBz sub = new FooBz(root0, "sub1");
this.begin();
this.persist(sub);
this.commit();
Assert.assertNotNull(sub.getId());
sub = new FooBz(root0, "sub2");
this.begin();
this.persist(sub);
this.commit();
Assert.assertNotNull(sub.getId());
Assert.assertEquals(root0, sub.getParent());
sub = new FooBz(root0, "sub3");
this.begin();
this.persist(sub);
this.commit();
Assert.assertNotNull(sub.getId());
Assert.assertEquals(root0.getId(), sub.getParent().getId());
FooBz root1 = this.getFooBz("000001");
sub = new FooBz(root1, "sub1");
this.begin();
this.persist(sub);
this.commit();
Assert.assertNotNull(sub.getId());
try {
sub = new FooBz(root1, "sub1");
this.begin();
this.persist(sub);
this.commit();
Assert.fail("Should not happen, because Unique Constraint");
} catch (Exception ignore) {
// expected
this.rollback();
}
sub = new FooBz(root1, "sub3");
this.begin();
this.persist(sub);
this.commit(); // fail here. don't know why
Assert.assertNotNull(sub.getId());
Assert.assertEquals("sub3", sub.getFbname());
this.close();
}
private static void execute(Connection c, String query) throws SQLException {
Statement s = c.createStatement();
s.execute(query);
s.close();
}
private FooBz getFooBz(String fbname) throws SQLException {
this.begin();
Query q = this.cq("SELECT i FROM FooBz i WHERE i.parent = i.id AND i.fbname = :fbname");
q.setParameter("fbname", fbname);
FooBz result = (FooBz) q.getSingleResult();
this.commit();
return result;
}
}FooBz.java
package org.batoo.jpa.core.test.foobz;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@Table(name = "FooBz",
uniqueConstraints = @UniqueConstraint(columnNames = { "fkParent", "fbname" }))
@Entity
@SuppressWarnings("serial")
public class FooBz implements Serializable {
@Column(name = "pkFooBz", nullable = false, unique = true, updatable = false)
@Id
@SequenceGenerator(allocationSize = 1, name = "FooBz_pkFooBz_seq",
sequenceName = "Foo_pkFooBz_seq")
@GeneratedValue(generator = "FooBz_pkFooBz_seq", strategy = GenerationType.SEQUENCE)
private Long id = null;
@JoinColumn(name = "fkParent", nullable = false)
@ManyToOne
private FooBz parent = null;
@Column(name = "fbname", nullable = false)
private String fbname = null;
protected FooBz() {
}
public FooBz(FooBz parent, String fbname) {
this.parent = parent;
this.fbname = fbname;
}
public Long getId() {
return id;
}
protected void setId(Long id) {
this.id = id;
}
public FooBz getParent() {
return parent;
}
public void setParent(FooBz parent) {
this.parent = parent;
}
public String getFbname() {
return fbname;
}
public void setFbname(String fbname) {
this.fbname = fbname;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj instanceof FooBz) {
final FooBz rhs = (FooBz) obj;
return getFbname().equals(rhs.getFbname()) && getParent().equals(rhs.getParent());
}
return false;
}
@Override
public int hashCode() {
return getFbname().hashCode();
}
}persistence.xml
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="default">
<provider>org.batoo.jpa.core.BatooPersistenceProvider</provider>
<class>org.batoo.jpa.core.test.foobz.FooBz</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="org.batoo.jpa.ddl" value="NONE" />
</properties>
</persistence-unit>
</persistence>Metadata
Metadata
Assignees
Labels
No labels