It turned out the whole problem was not being able to find "version". I still don't understand why I didn't see that exception in the console, and I am quite sure it wasn't there (even with all log levels set to Trace). After failing to find it, OpenJPA didn't create any tables (including OPENJPA_SEQUENCE_TABLE), and OPENJPA_SEQUENCE_TABLE simply happened to be the first table it queried in my test.
Stripping delimiters later was done for two reasons: 1) better looking generated SQL; 2) going back to @UniqueConstraint(columnNames = { "name", "version" })). What's the reasoning for DBIdentifierUtilImpl.makeIdentifierValid uppercasing all non-delimited identifiers, by the way? On Wed, Jun 13, 2012 at 11:26 PM, Kevin Sutter [via OpenJPA] <ml-node+s208410n7580279...@n2.nabble.com> wrote: > Thanks, Alexey, for your debugging efforts. This seems to indicate an > issue with our delimited identifier support. One clarification, when you > said that changing the UniqueConstraint fixed the problem, did you mean > just the JUnit exception that you posted about not able to find "version", > or did it fix both of your issues? > > @UniqueConstraint(columnNames = { "name", "\"version\"" })) > > I'm assuming it only resolved the JUnit exception since you still had to > hack another solution with stripping the delimiters... > > Thanks, > Kevin > > On Wed, Jun 13, 2012 at 3:00 AM, Alexey Romanov > <[hidden email]>wrote: > >> So the problem is that if I don't delimit column names, >> DBIdentifierUtilImpl.makeIdentifierValid (called from >> dict.getValidColumnName) will convert them to upper case, whether I want >> it >> or not. The ugly solution I came up with is to delimit them and strip the >> delimiters later. Unfortunately, this leads to code duplication :( This is >> what I have at the moment: >> >> >> package ru.focusmedia.odp.server.datastore.jpa.impl; >> >> import org.apache.openjpa.jdbc.identifier.DBIdentifier; >> import org.apache.openjpa.jdbc.identifier.Normalizer; >> import org.apache.openjpa.jdbc.meta.FieldMapping; >> import org.apache.openjpa.jdbc.meta.ValueMapping; >> import org.apache.openjpa.jdbc.schema.Column; >> import org.apache.openjpa.jdbc.schema.Table; >> import org.apache.openjpa.meta.JavaTypes; >> import org.apache.openjpa.persistence.jdbc.PersistenceMappingDefaults; >> >> public class ImprovedMappingDefaults extends PersistenceMappingDefaults { >> @Override >> protected void correctName(Table table, Column col) { >> String originalName = col.getIdentifier().getName(); >> boolean wasOriginallyDelimited = >> Normalizer.isDelimited(originalName); >> DBIdentifier name = DBIdentifier.newColumn(originalName, >> !wasOriginallyDelimited); >> DBIdentifier validName = dict.getValidColumnName(name, >> table); >> validName = addUnderscores(validName, >> wasOriginallyDelimited); >> col.setIdentifier(validName); >> table.addCorrectedColumnName(validName, true); >> } >> >> @Override >> public void populateJoinColumn(FieldMapping fm, Table local, Table >> foreign, >> Column col, Object target, int pos, int cols) { >> if (!(target instanceof Column)) >> return; >> >> // if this is a bidi relation, prefix with inverse field >> name, else >> // prefix with owning entity name >> FieldMapping[] inverses = fm.getInverseMappings(); >> DBIdentifier sName = DBIdentifier.NULL; >> String originalName = inverses.length > 0 ? >> inverses[0].getName() : fm >> .getDefiningMapping().getTypeAlias(); >> boolean wasOriginallyDelimited = >> Normalizer.isDelimited(originalName); >> sName = DBIdentifier.newColumn(originalName, >> !wasOriginallyDelimited); >> DBIdentifier targetName = ((Column) >> target).getIdentifier(); >> DBIdentifier tempName = DBIdentifier.NULL; >> if ((sName.length() + targetName.length()) >= >> dict.maxColumnNameLength) { >> tempName = DBIdentifier.truncate(sName, >> dict.maxColumnNameLength >> - targetName.length() - 1); >> } >> // suffix with '_' + target column >> if (DBIdentifier.isNull(tempName)) >> tempName = sName; >> sName = DBIdentifier.combine(tempName, >> targetName.getName()); >> sName = dict.getValidColumnName(sName, foreign); >> sName = addUnderscores(sName, wasOriginallyDelimited); >> col.setIdentifier(sName); >> } >> >> @Override >> public void populateForeignKeyColumn(ValueMapping vm, DBIdentifier >> sName, >> Table local, Table foreign, Column col, Object target, boolean >> inverse, >> int pos, int cols) { >> boolean elem = vm == vm.getFieldMapping().getElement() >> && vm.getFieldMapping().getTypeCode() != JavaTypes.MAP; >> >> // if this is a non-inverse collection element key, it must be >> in >> // a join table: if we're not prepending the field name, leave >> the >> // default >> if (!getPrependFieldNameToJoinTableInverseJoinColumns() && >> !inverse && elem) >> return; >> >> // otherwise jpa always uses <field>_<pkcol> for column name, >> even >> // when only one col >> if (target instanceof Column) { >> if (DBIdentifier.isNull(sName)) { >> sName = col.getIdentifier(); >> } else { >> String originalName = elem ? >> vm.getFieldMapping().getName() : >> Normalizer.removeHungarianNotation(sName.getName()); >> boolean wasOriginallyDelimited = >> Normalizer.isDelimited(originalName); >> sName = DBIdentifier.newColumn(originalName, >> !wasOriginallyDelimited); >> sName = DBIdentifier.combine(sName, >> ((Column)target).getIdentifier().getName()); >> >> // No need to check for uniqueness. >> sName = dict.getValidColumnName(sName, local, false); >> sName = addUnderscores(sName, >> wasOriginallyDelimited); >> } >> col.setIdentifier(sName); >> } >> } >> >> private DBIdentifier addUnderscores(DBIdentifier sName, >> boolean wasOriginallyDelimited) { >> String nameWithUnderscores = >> addUnderscores(sName.getName()); >> if (!wasOriginallyDelimited) { >> nameWithUnderscores = Normalizer >> >> .removeDelimiters(nameWithUnderscores); >> } >> sName = DBIdentifier.newColumn(nameWithUnderscores, false); >> return sName; >> } >> >> // taken from Hibernate's ImprovedNamingStrategy >> private static String addUnderscores(String name) { >> StringBuilder buf = new StringBuilder(name.replace('.', >> '_')); >> for (int i = 1; i < buf.length() - 1; i++) { >> if (Character.isLowerCase(buf.charAt(i - 1)) >> && >> Character.isUpperCase(buf.charAt(i)) >> && >> Character.isLowerCase(buf.charAt(i + 1))) { >> buf.insert(i++, '_'); >> } >> } >> return buf.toString().toLowerCase(); >> } >> } >> >> >> -- >> View this message in context: >> >> http://openjpa.208410.n2.nabble.com/Change-of-MappingDefaults-breaks-OPENJPA-SEQUENCE-TABLE-tp7580246p7580270.html >> Sent from the OpenJPA Users mailing list archive at Nabble.com. >> > > > ________________________________ > If you reply to this email, your message will be added to the discussion > below: > http://openjpa.208410.n2.nabble.com/Change-of-MappingDefaults-breaks-OPENJPA-SEQUENCE-TABLE-tp7580246p7580279.html > To unsubscribe from Change of MappingDefaults breaks OPENJPA_SEQUENCE_TABLE, > click here. > NAML -- View this message in context: http://openjpa.208410.n2.nabble.com/Change-of-MappingDefaults-breaks-OPENJPA-SEQUENCE-TABLE-tp7580246p7580281.html Sent from the OpenJPA Users mailing list archive at Nabble.com.