mirror of https://github.com/apache/openjpa.git
OPENJPA-1235 Added support for named unique constraints
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@802864 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
538f1fd084
commit
9af553bc8d
|
@ -92,6 +92,7 @@ public class TableJDBCSeq
|
||||||
private String _seqColumnName = "SEQUENCE_VALUE";
|
private String _seqColumnName = "SEQUENCE_VALUE";
|
||||||
private String _pkColumnName = "ID";
|
private String _pkColumnName = "ID";
|
||||||
private String[] _uniqueColumnNames;
|
private String[] _uniqueColumnNames;
|
||||||
|
private String _uniqueConstraintName;
|
||||||
|
|
||||||
private Column _seqColumn = null;
|
private Column _seqColumn = null;
|
||||||
private Column _pkColumn = null;
|
private Column _pkColumn = null;
|
||||||
|
@ -397,7 +398,10 @@ public class TableJDBCSeq
|
||||||
_seqColumn.setJavaType(JavaTypes.LONG);
|
_seqColumn.setJavaType(JavaTypes.LONG);
|
||||||
|
|
||||||
if (_uniqueColumnNames != null) {
|
if (_uniqueColumnNames != null) {
|
||||||
String uniqueName = dict.getValidUniqueName("UNQ", table);
|
String uniqueName = _uniqueConstraintName;
|
||||||
|
if (StringUtils.isEmpty(uniqueName)) {
|
||||||
|
uniqueName = dict.getValidUniqueName("UNQ", table);
|
||||||
|
}
|
||||||
Unique u = table.addUnique(uniqueName);
|
Unique u = table.addUnique(uniqueName);
|
||||||
for (String columnName : _uniqueColumnNames) {
|
for (String columnName : _uniqueColumnNames) {
|
||||||
if (!table.containsColumn(columnName))
|
if (!table.containsColumn(columnName))
|
||||||
|
@ -805,6 +809,14 @@ public class TableJDBCSeq
|
||||||
return dict.getLong(rs, 1);
|
return dict.getLong(rs, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUniqueConstraintName(String _uniqueConstraintName) {
|
||||||
|
this._uniqueConstraintName = _uniqueConstraintName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUniqueConstraintName() {
|
||||||
|
return _uniqueConstraintName;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AllocateSequenceRunnable is a runnable wrapper that will inserts the
|
* AllocateSequenceRunnable is a runnable wrapper that will inserts the
|
||||||
* initial sequence value into the database.
|
* initial sequence value into the database.
|
||||||
|
|
|
@ -62,6 +62,7 @@ public class SequenceMapping
|
||||||
private static final String PROP_PK_COL = "PrimaryKeyColumn";
|
private static final String PROP_PK_COL = "PrimaryKeyColumn";
|
||||||
private static final String PROP_PK_VALUE = "PrimaryKeyValue";
|
private static final String PROP_PK_VALUE = "PrimaryKeyValue";
|
||||||
private static final String PROP_UNIQUE = "UniqueColumns";
|
private static final String PROP_UNIQUE = "UniqueColumns";
|
||||||
|
private static final String PROP_UNIQUE_CONSTRAINT = "UniqueConstraintName";
|
||||||
|
|
||||||
private File _mapFile = null;
|
private File _mapFile = null;
|
||||||
private String _table = null;
|
private String _table = null;
|
||||||
|
@ -69,6 +70,7 @@ public class SequenceMapping
|
||||||
private String _primaryKeyColumn = null;
|
private String _primaryKeyColumn = null;
|
||||||
private String _primaryKeyValue = null;
|
private String _primaryKeyValue = null;
|
||||||
private String[] _uniqueColumns = null;
|
private String[] _uniqueColumns = null;
|
||||||
|
private String _uniqueConstraintName = null;
|
||||||
|
|
||||||
public SequenceMapping(String name, MappingRepository repos) {
|
public SequenceMapping(String name, MappingRepository repos) {
|
||||||
super(name, repos);
|
super(name, repos);
|
||||||
|
@ -175,6 +177,12 @@ public class SequenceMapping
|
||||||
// Array of unique column names are passed to configuration
|
// Array of unique column names are passed to configuration
|
||||||
// as a single string "x|y|z". The configurable (TableJDBCSeq) must
|
// as a single string "x|y|z". The configurable (TableJDBCSeq) must
|
||||||
// parse it back.
|
// parse it back.
|
||||||
|
if (_uniqueConstraintName != null &&
|
||||||
|
_uniqueConstraintName.length() > 0) {
|
||||||
|
appendProperty(props, PROP_UNIQUE_CONSTRAINT,
|
||||||
|
addQuotes(_uniqueConstraintName));
|
||||||
|
}
|
||||||
|
|
||||||
if (_uniqueColumns != null && _uniqueColumns.length > 0)
|
if (_uniqueColumns != null && _uniqueColumns.length > 0)
|
||||||
appendProperty(props, PROP_UNIQUE,
|
appendProperty(props, PROP_UNIQUE,
|
||||||
StringUtils.join(_uniqueColumns,'|'));
|
StringUtils.join(_uniqueColumns,'|'));
|
||||||
|
@ -186,4 +194,14 @@ public class SequenceMapping
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUniqueConstraintName(String name) {
|
||||||
|
_uniqueConstraintName = name;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUniqueConstraintName() {
|
||||||
|
return _uniqueConstraintName;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,6 +277,7 @@ public class AnnotationPersistenceMappingParser
|
||||||
break; // nothing to do
|
break; // nothing to do
|
||||||
case 1:
|
case 1:
|
||||||
meta.setUniqueColumns(gen.uniqueConstraints()[0].columnNames());
|
meta.setUniqueColumns(gen.uniqueConstraints()[0].columnNames());
|
||||||
|
meta.setUniqueConstraintName(gen.uniqueConstraints()[0].name());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
log.warn(_loc.get("unique-many-on-seq-unsupported", el, name));
|
log.warn(_loc.get("unique-many-on-seq-unsupported", el, name));
|
||||||
|
@ -558,6 +559,10 @@ public class AnnotationPersistenceMappingParser
|
||||||
column.setName(columnNames[i]);
|
column.setName(columnNames[i]);
|
||||||
uniqueConstraint.addColumn(column);
|
uniqueConstraint.addColumn(column);
|
||||||
}
|
}
|
||||||
|
String name = anno.name();
|
||||||
|
if (!StringUtils.isEmpty(name)) {
|
||||||
|
uniqueConstraint.setName(name);
|
||||||
|
}
|
||||||
return uniqueConstraint;
|
return uniqueConstraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -601,6 +601,9 @@ public class AnnotationPersistenceMappingSerializer
|
||||||
if (columns.length > 1)
|
if (columns.length > 1)
|
||||||
sb.insert(0, "{").append("}");
|
sb.insert(0, "{").append("}");
|
||||||
ab.add("columnNames", sb.toString());
|
ab.add("columnNames", sb.toString());
|
||||||
|
if (StringUtils.isNotEmpty(unique.getName())) {
|
||||||
|
ab.add("name", unique.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -96,6 +96,7 @@ enum MappingTag {
|
||||||
MAP_KEY_TEMPORAL,
|
MAP_KEY_TEMPORAL,
|
||||||
MAPPING_OVERRIDE,
|
MAPPING_OVERRIDE,
|
||||||
MAPPING_OVERRIDES,
|
MAPPING_OVERRIDES,
|
||||||
|
NAME,
|
||||||
NONPOLY,
|
NONPOLY,
|
||||||
ORDER_COL,
|
ORDER_COL,
|
||||||
STRAT,
|
STRAT,
|
||||||
|
|
|
@ -99,6 +99,7 @@ public class XMLPersistenceMappingParser
|
||||||
_elems.put("map-key-column", MAP_KEY_COL);
|
_elems.put("map-key-column", MAP_KEY_COL);
|
||||||
_elems.put("map-key-join-column", MAP_KEY_JOIN_COL);
|
_elems.put("map-key-join-column", MAP_KEY_JOIN_COL);
|
||||||
_elems.put("map-key-temporal", MAP_KEY_TEMPORAL);
|
_elems.put("map-key-temporal", MAP_KEY_TEMPORAL);
|
||||||
|
_elems.put("name", NAME);
|
||||||
_elems.put("order-column", ORDER_COLUMN);
|
_elems.put("order-column", ORDER_COLUMN);
|
||||||
_elems.put("primary-key-join-column", PK_JOIN_COL);
|
_elems.put("primary-key-join-column", PK_JOIN_COL);
|
||||||
_elems.put("secondary-table", SECONDARY_TABLE);
|
_elems.put("secondary-table", SECONDARY_TABLE);
|
||||||
|
@ -249,6 +250,9 @@ public class XMLPersistenceMappingParser
|
||||||
case UNIQUE:
|
case UNIQUE:
|
||||||
ret = startUniqueConstraint(attrs);
|
ret = startUniqueConstraint(attrs);
|
||||||
break;
|
break;
|
||||||
|
case NAME:
|
||||||
|
ret = true;
|
||||||
|
break;
|
||||||
case TEMPORAL:
|
case TEMPORAL:
|
||||||
case ENUMERATED:
|
case ENUMERATED:
|
||||||
case MAP_KEY_ENUMERATED:
|
case MAP_KEY_ENUMERATED:
|
||||||
|
@ -285,6 +289,19 @@ public class XMLPersistenceMappingParser
|
||||||
return (ret) ? tag : null;
|
return (ret) ? tag : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean endName() {
|
||||||
|
String name = this.currentText();
|
||||||
|
if (StringUtils.isNotEmpty(name)) {
|
||||||
|
Object current = currentElement();
|
||||||
|
if (current instanceof Unique) {
|
||||||
|
Unique unq = (Unique)current;
|
||||||
|
unq.setName(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void endClassMappingElement(String name)
|
protected void endClassMappingElement(String name)
|
||||||
throws SAXException {
|
throws SAXException {
|
||||||
|
@ -333,6 +350,9 @@ public class XMLPersistenceMappingParser
|
||||||
case TABLE_GEN:
|
case TABLE_GEN:
|
||||||
endTableGenerator();
|
endTableGenerator();
|
||||||
break;
|
break;
|
||||||
|
case NAME:
|
||||||
|
endName();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1130,6 +1150,14 @@ public class XMLPersistenceMappingParser
|
||||||
private boolean startUniqueConstraint(Attributes attrs)
|
private boolean startUniqueConstraint(Attributes attrs)
|
||||||
throws SAXException {
|
throws SAXException {
|
||||||
Unique unique = new Unique();
|
Unique unique = new Unique();
|
||||||
|
// TODO JRB: If the spec is corrected, get the unique constraint name
|
||||||
|
// via attribute
|
||||||
|
/*
|
||||||
|
String name = attrs.getValue("name");
|
||||||
|
if (StringUtils.isNotEmpty(name)) {
|
||||||
|
unique.setName(name);
|
||||||
|
}
|
||||||
|
*/
|
||||||
pushElement(unique);
|
pushElement(unique);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1161,6 +1189,9 @@ public class XMLPersistenceMappingParser
|
||||||
for (Column uniqueColumn : uniqueColumns)
|
for (Column uniqueColumn : uniqueColumns)
|
||||||
columnNames[i++] = uniqueColumn.getName();
|
columnNames[i++] = uniqueColumn.getName();
|
||||||
seq.setUniqueColumns(columnNames);
|
seq.setUniqueColumns(columnNames);
|
||||||
|
if (StringUtils.isNotEmpty(unique.getName())) {
|
||||||
|
seq.setUniqueConstraintName(unique.getName());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new InternalException();
|
throw new InternalException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -566,6 +566,14 @@ public class XMLPersistenceMappingSerializer
|
||||||
}
|
}
|
||||||
|
|
||||||
private void serializeUniqueConstraint(Unique unique) throws SAXException {
|
private void serializeUniqueConstraint(Unique unique) throws SAXException {
|
||||||
|
if (StringUtils.isNotEmpty(unique.getName())) {
|
||||||
|
//TODO JRB: If the spec is modified to use a name attribute
|
||||||
|
// remove the element def and uncomment the attribute def
|
||||||
|
startElement("name");
|
||||||
|
addText(unique.getName());
|
||||||
|
endElement("name");
|
||||||
|
// addAttribute("name", unique.getName());
|
||||||
|
}
|
||||||
startElement("unique-constraint");
|
startElement("unique-constraint");
|
||||||
Column[] columns = unique.getColumns();
|
Column[] columns = unique.getColumns();
|
||||||
for (Column column:columns) {
|
for (Column column:columns) {
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.persistence.jdbc.unique;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.JoinTable;
|
||||||
|
import javax.persistence.ManyToMany;
|
||||||
|
import javax.persistence.SecondaryTable;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.UniqueConstraint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data structures for testing unique constraint settings on ORM Annotations.
|
||||||
|
* @UniqueConstraint annotation is declared at class-level with
|
||||||
|
* @Table,
|
||||||
|
* @SecondaryTable annotations
|
||||||
|
* and at field-level with
|
||||||
|
* @JoinTable annotation.
|
||||||
|
* also with
|
||||||
|
* @Column(unique=true) on single column.
|
||||||
|
*
|
||||||
|
* The columns included in unique constraint must be non-nullable. This is
|
||||||
|
* recommended that the non-nullability of the column is explictly set by the
|
||||||
|
* user, though the implementation forces a column to non-nullable as a column
|
||||||
|
* is included in a unique constraint.
|
||||||
|
*
|
||||||
|
* The name of the constraint is generated by the implementation as JPA ORM
|
||||||
|
* specification has not allowed to specify a name for the constraint via the
|
||||||
|
* annotation or XML descriptor. Some databases allow two constraints having the
|
||||||
|
* same name but applied to different tables, while some other databases do not.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Pinaki Poddar
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Entity
|
||||||
|
@Table(name="N_UNIQUE_A",
|
||||||
|
uniqueConstraints={@UniqueConstraint(name="uca_f1_f2", columnNames={"f1","f2"}),
|
||||||
|
@UniqueConstraint(name="uca_f3_f4", columnNames={"f3","f4"})})
|
||||||
|
@SecondaryTable(name="N_UNIQUE_SECONDARY",
|
||||||
|
uniqueConstraints=@UniqueConstraint(name="uca_sf1", columnNames={"sf1"}))
|
||||||
|
|
||||||
|
public class NamedUniqueA {
|
||||||
|
@Id
|
||||||
|
private int aid;
|
||||||
|
|
||||||
|
// Same named field in UniqueB also is defined as unique
|
||||||
|
@Column(unique=true, nullable=false)
|
||||||
|
private int f1;
|
||||||
|
|
||||||
|
@Column(nullable=false)
|
||||||
|
private int f2;
|
||||||
|
|
||||||
|
@Column(nullable=false)
|
||||||
|
private int f3;
|
||||||
|
|
||||||
|
@Column(nullable=false)
|
||||||
|
private int f4;
|
||||||
|
|
||||||
|
private int f5;
|
||||||
|
private int f6;
|
||||||
|
|
||||||
|
@Column(table="N_UNIQUE_SECONDARY", nullable=false)
|
||||||
|
private short sf1;
|
||||||
|
|
||||||
|
@Column(table="N_UNIQUE_SECONDARY")
|
||||||
|
private short sf2;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(name="N_UNIQUE_JOINTABLE",
|
||||||
|
joinColumns={@JoinColumn(name="FK_A", nullable=false,
|
||||||
|
referencedColumnName="aid")},
|
||||||
|
inverseJoinColumns={@JoinColumn(name="FK_B", nullable=false,
|
||||||
|
referencedColumnName="bid")},
|
||||||
|
uniqueConstraints=@UniqueConstraint(name="uca_fka_fkb", columnNames={"FK_A","FK_B"}))
|
||||||
|
private Collection<NamedUniqueB> bs;
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.persistence.jdbc.unique;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name="N_UNIQUE_B",
|
||||||
|
uniqueConstraints={@UniqueConstraint(name="ucb_f1_f2", columnNames={"f1","f2"})})
|
||||||
|
public class NamedUniqueB {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy=GenerationType.TABLE, generator="namedTestGenerator")
|
||||||
|
@TableGenerator(name="namedTestGenerator", table="N_UNIQUE_GENERATOR",
|
||||||
|
pkColumnName="GEN1", valueColumnName="GEN2",
|
||||||
|
uniqueConstraints={@UniqueConstraint(name="ucb_gen1_gen2", columnNames={"GEN1","GEN2"})})
|
||||||
|
private int bid;
|
||||||
|
|
||||||
|
// Same named field in UniqueA also is defined as unique
|
||||||
|
@Column(unique=true, nullable=false)
|
||||||
|
private int f1;
|
||||||
|
|
||||||
|
@Column(nullable=false)
|
||||||
|
private int f2;
|
||||||
|
|
||||||
|
@CollectionTable(name="N_U_COLL_TBL", uniqueConstraints=
|
||||||
|
{@UniqueConstraint(name="ucb_f3", columnNames="f3")})
|
||||||
|
@ElementCollection
|
||||||
|
@Column(name="f3", nullable=false)
|
||||||
|
private Set<String> f3;
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.persistence.jdbc.unique;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
|
||||||
|
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
|
||||||
|
import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
|
||||||
|
import org.apache.openjpa.persistence.jdbc.SQLSniffer;
|
||||||
|
import org.apache.openjpa.persistence.test.SQLListenerTestCase;
|
||||||
|
|
||||||
|
public class TestNamedUniqueConstraint extends SQLListenerTestCase {
|
||||||
|
@Override
|
||||||
|
public void setUp(Object... props) {
|
||||||
|
super.setUp(DROP_TABLES, NamedUniqueA.class, NamedUniqueB.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapping() {
|
||||||
|
|
||||||
|
// If the database does not support unique constraints, exit
|
||||||
|
if (!supportsUniqueConstraints())
|
||||||
|
return;
|
||||||
|
|
||||||
|
EntityManager em = emf.createEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.getTransaction().commit();
|
||||||
|
em.close();
|
||||||
|
// The above should trigger schema definition
|
||||||
|
|
||||||
|
List<String> sqls = super.sql;
|
||||||
|
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE N_UNIQUE_A",
|
||||||
|
"uca_f1_f2 UNIQUE .*\\(f1, f2\\)",
|
||||||
|
"uca_f3_f4 UNIQUE .*\\(f3, f4\\).*");
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE N_UNIQUE_B",
|
||||||
|
"ucb_f1_f2 UNIQUE .*\\(f1, f2\\).*");
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE N_UNIQUE_SECONDARY",
|
||||||
|
"uca_sf1 UNIQUE .*\\(sf1\\)");
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE N_UNIQUE_GENERATOR",
|
||||||
|
"ucb_gen1_gen2 UNIQUE .*\\(GEN1, GEN2\\)");
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE N_UNIQUE_JOINTABLE",
|
||||||
|
"uca_fka_fkb UNIQUE .*\\(FK_A, FK_B\\)");
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE N_U_COLL_TBL",
|
||||||
|
"ucb_f3 UNIQUE .*\\(f3\\).*");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean supportsUniqueConstraints() {
|
||||||
|
OpenJPAEntityManagerFactorySPI emfs = (OpenJPAEntityManagerFactorySPI)emf;
|
||||||
|
JDBCConfiguration jdbccfg = (JDBCConfiguration)emfs.getConfiguration();
|
||||||
|
return jdbccfg.getDBDictionaryInstance().supportsUniqueConstraints;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assertSQLFragnments(List<String> list, String... keys) {
|
||||||
|
if (SQLSniffer.matches(list, keys))
|
||||||
|
return;
|
||||||
|
fail("None of the following " + sql.size() + " SQL \r\n" +
|
||||||
|
toString(sql) + "\r\n contains all keys \r\n"
|
||||||
|
+ toString(Arrays.asList(keys)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.openjpa.persistence.jdbc.unique;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
|
||||||
|
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
|
||||||
|
import org.apache.openjpa.persistence.OpenJPAEntityManagerSPI;
|
||||||
|
import org.apache.openjpa.persistence.jdbc.SQLSniffer;
|
||||||
|
import org.apache.openjpa.persistence.test.SQLListenerTestCase;
|
||||||
|
|
||||||
|
public class TestNamedUniqueConstraintWithXMLDescriptor extends SQLListenerTestCase {
|
||||||
|
@Override
|
||||||
|
public void setUp(Object... props) {
|
||||||
|
super.setUp(DROP_TABLES, NamedUniqueA.class, NamedUniqueB.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getPersistenceUnitName() {
|
||||||
|
return "NamedUniqueConstraintTest";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapping() {
|
||||||
|
|
||||||
|
// If the database does not support unique constraints, exit
|
||||||
|
if (!supportsUniqueConstraints())
|
||||||
|
return;
|
||||||
|
|
||||||
|
EntityManager em = emf.createEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.getTransaction().commit();
|
||||||
|
em.close();
|
||||||
|
// The above should trigger schema definition
|
||||||
|
|
||||||
|
List<String> sqls = super.sql;
|
||||||
|
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE NX_UNIQUE_A",
|
||||||
|
"ucxa_f1_f2 UNIQUE .*\\(f1x, f2x\\)",
|
||||||
|
"ucxa_f3_f4 UNIQUE .*\\(f3x, f4x\\).*");
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE NX_UNIQUE_B",
|
||||||
|
"ucxb_f1_f2 UNIQUE .*\\(f1x, f2x\\).*");
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE NX_UNIQUE_SECONDARY",
|
||||||
|
"ucxa_sf1 UNIQUE .*\\(sf1x\\)");
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE NX_UNIQUE_GENERATOR",
|
||||||
|
"ucxb_gen1_gen2 UNIQUE .*\\(GEN1_XML, GEN2_XML\\)");
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE NX_UNIQUE_JOINTABLE",
|
||||||
|
"ucxa_fka_fkb UNIQUE .*\\(FK_A_XML, FK_B_XML\\)");
|
||||||
|
assertSQLFragnments(sqls, "CREATE TABLE NX_U_COLL_TBL",
|
||||||
|
"ucxb_f3 UNIQUE .*\\(f3x\\).*");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean supportsUniqueConstraints() {
|
||||||
|
OpenJPAEntityManagerFactorySPI emfs = (OpenJPAEntityManagerFactorySPI)emf;
|
||||||
|
JDBCConfiguration jdbccfg = (JDBCConfiguration)emfs.getConfiguration();
|
||||||
|
return jdbccfg.getDBDictionaryInstance().supportsUniqueConstraints;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assertSQLFragnments(List<String> list, String... keys) {
|
||||||
|
if (SQLSniffer.matches(list, keys))
|
||||||
|
return;
|
||||||
|
fail("None of the following " + sql.size() + " SQL \r\n" +
|
||||||
|
toString(sql) + "\r\n contains all keys \r\n"
|
||||||
|
+ toString(Arrays.asList(keys)));
|
||||||
|
}
|
||||||
|
}
|
|
@ -221,4 +221,15 @@
|
||||||
</properties>
|
</properties>
|
||||||
</persistence-unit>
|
</persistence-unit>
|
||||||
|
|
||||||
|
<persistence-unit name="NamedUniqueConstraintTest" transaction-type="RESOURCE_LOCAL">
|
||||||
|
<description>PU for order named unique constraint testing</description>
|
||||||
|
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
|
||||||
|
<mapping-file>org/apache/openjpa/persistence/jdbc/unique/named-constraint-orm.xml</mapping-file>
|
||||||
|
<class>org.apache.openjpa.persistence.jdbc.unique.NamedUniqueA</class>
|
||||||
|
<class>org.apache.openjpa.persistence.jdbc.unique.NamedUniqueB</class>
|
||||||
|
<properties>
|
||||||
|
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
|
||||||
|
</properties>
|
||||||
|
</persistence-unit>
|
||||||
|
|
||||||
</persistence>
|
</persistence>
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance
|
||||||
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the License is distributed on an
|
||||||
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
-->
|
||||||
|
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence orm_2_0.xsd"
|
||||||
|
version="2.0">
|
||||||
|
|
||||||
|
<persistence-unit-metadata>
|
||||||
|
<xml-mapping-metadata-complete/>
|
||||||
|
</persistence-unit-metadata>
|
||||||
|
|
||||||
|
|
||||||
|
<package>org.apache.openjpa.persistence.jdbc.unique</package>
|
||||||
|
<entity name="NamedUniqueA" class="NamedUniqueA">
|
||||||
|
<table name="NX_UNIQUE_A">
|
||||||
|
<unique-constraint>
|
||||||
|
<name>ucxa_f1_f2</name>
|
||||||
|
<column-name>f1x</column-name>
|
||||||
|
<column-name>f2x</column-name>
|
||||||
|
</unique-constraint>
|
||||||
|
<unique-constraint>
|
||||||
|
<name>ucxa_f3_f4</name>
|
||||||
|
<column-name>f3x</column-name>
|
||||||
|
<column-name>f4x</column-name>
|
||||||
|
</unique-constraint>
|
||||||
|
</table>
|
||||||
|
<secondary-table name="NX_UNIQUE_SECONDARY">
|
||||||
|
<unique-constraint>
|
||||||
|
<name>ucxa_sf1</name>
|
||||||
|
<column-name>sf1x</column-name>
|
||||||
|
</unique-constraint>
|
||||||
|
</secondary-table>
|
||||||
|
<attributes>
|
||||||
|
<id name="aid">
|
||||||
|
</id>
|
||||||
|
<basic name="f1">
|
||||||
|
<column name="f1x" unique="true"/>
|
||||||
|
</basic>
|
||||||
|
<basic name="f2">
|
||||||
|
<column name="f2x"/>
|
||||||
|
</basic>
|
||||||
|
<basic name="f3">
|
||||||
|
<column name="f3x"/>
|
||||||
|
</basic>
|
||||||
|
<basic name="f4">
|
||||||
|
<column name="f4x"/>
|
||||||
|
</basic>
|
||||||
|
<basic name="f5">
|
||||||
|
<column name="f5x"/>
|
||||||
|
</basic>
|
||||||
|
<basic name="f6">
|
||||||
|
<column name="f6x"/>
|
||||||
|
</basic>
|
||||||
|
<basic name="sf1">
|
||||||
|
<column name="sf1x" table="NX_UNIQUE_SECONDARY" />
|
||||||
|
</basic>
|
||||||
|
<basic name="sf2">
|
||||||
|
<column name="sf2x" table="NX_UNIQUE_SECONDARY" />
|
||||||
|
</basic>
|
||||||
|
|
||||||
|
<many-to-many name="bs">
|
||||||
|
<join-table name="NX_UNIQUE_JOINTABLE">
|
||||||
|
<join-column name="FK_A_XML" referenced-column-name="aid" nullable="false"/>
|
||||||
|
<inverse-join-column name="FK_B_XML" referenced-column-name="bid" nullable="false"/>
|
||||||
|
<unique-constraint>
|
||||||
|
<name>ucxa_fka_fkb</name>
|
||||||
|
<column-name>FK_A_XML</column-name>
|
||||||
|
<column-name>FK_B_XML</column-name>
|
||||||
|
</unique-constraint>
|
||||||
|
</join-table>
|
||||||
|
</many-to-many>
|
||||||
|
</attributes>
|
||||||
|
</entity>
|
||||||
|
|
||||||
|
<entity name="NamedUniqueB" class="NamedUniqueB">
|
||||||
|
<table name="NX_UNIQUE_B">
|
||||||
|
<unique-constraint>
|
||||||
|
<name>ucxb_f1_f2</name>
|
||||||
|
<column-name>f1x</column-name>
|
||||||
|
<column-name>f2x</column-name>
|
||||||
|
</unique-constraint>
|
||||||
|
</table>
|
||||||
|
<attributes>
|
||||||
|
<id name="bid">
|
||||||
|
<generated-value strategy="TABLE"
|
||||||
|
generator="testGeneratorXML" />
|
||||||
|
<table-generator name="testGeneratorXML"
|
||||||
|
table="NX_UNIQUE_GENERATOR" pk-column-name="GEN1_XML"
|
||||||
|
value-column-name="GEN2_XML">
|
||||||
|
<unique-constraint>
|
||||||
|
<name>ucxb_gen1_gen2</name>
|
||||||
|
<column-name>GEN1_XML</column-name>
|
||||||
|
<column-name>GEN2_XML</column-name>
|
||||||
|
</unique-constraint>
|
||||||
|
</table-generator>
|
||||||
|
</id>
|
||||||
|
<basic name="f1">
|
||||||
|
<column name="f1x" unique="true"/>
|
||||||
|
</basic>
|
||||||
|
<basic name="f2">
|
||||||
|
<column name="f2x"/>
|
||||||
|
</basic>
|
||||||
|
<element-collection name="f3">
|
||||||
|
<column name="f3x" nullable="false"/>
|
||||||
|
<collection-table name="NX_U_COLL_TBL">
|
||||||
|
<unique-constraint>
|
||||||
|
<name>ucxb_f3</name>
|
||||||
|
<column-name>f3x</column-name>
|
||||||
|
</unique-constraint>
|
||||||
|
</collection-table>
|
||||||
|
</element-collection>
|
||||||
|
</attributes>
|
||||||
|
</entity>
|
||||||
|
</entity-mappings>
|
|
@ -363,11 +363,17 @@ is sent to the database before the SQL inserting <literal>B</literal> to avoid a
|
||||||
unique constraint violation.
|
unique constraint violation.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
<classname>UniqueConstraint</classname> has a single property:
|
<classname>UniqueConstraint</classname> has these properties:
|
||||||
</para>
|
</para>
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
|
<literal>String name</literal>: The name of the constraint. OpenJPA will choose
|
||||||
|
a name if you do not provide one, or will create an anonymous constraint.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
<literal>String[] columnNames</literal>: The names of the columns the
|
<literal>String[] columnNames</literal>: The names of the columns the
|
||||||
constraint spans.
|
constraint spans.
|
||||||
</para>
|
</para>
|
||||||
|
@ -390,7 +396,7 @@ column of the <literal>ART</literal> table:
|
||||||
</para>
|
</para>
|
||||||
<programlisting>
|
<programlisting>
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name="ART", uniqueConstraints=@Unique(columnNames="TITLE"))
|
@Table(name="ART", uniqueConstraints=@UniqueConstraint(name="TITLE_CNSTR", columnNames="TITLE"))
|
||||||
public class Article {
|
public class Article {
|
||||||
...
|
...
|
||||||
}
|
}
|
||||||
|
@ -402,6 +408,7 @@ The same metadata expressed in XML form:
|
||||||
<entity class="org.mag.Article">
|
<entity class="org.mag.Article">
|
||||||
<table name="ART">
|
<table name="ART">
|
||||||
<unique-constraint>
|
<unique-constraint>
|
||||||
|
<name>TITLE_CNSTR</name>
|
||||||
<column-name>TITLE</column-name>
|
<column-name>TITLE</column-name>
|
||||||
</unique-constraint>
|
</unique-constraint>
|
||||||
</table>
|
</table>
|
||||||
|
|
Loading…
Reference in New Issue