private void buildColumnAnnotation( Selectable selectable, StringBuffer annotations, boolean insertable, boolean updatable) { if (selectable.isFormula()) { annotations .append("@") .append(importType("org.hibernate.annotations.Formula")) .append("(value=\"") .append(selectable.getText()) .append("\")"); } else { Column column = (Column) selectable; annotations .append("@" + importType("javax.persistence.Column") + "(name=\"") .append(column.getName()) .append("\""); appendCommonColumnInfo(annotations, column, insertable, updatable); if (column.getPrecision() != Column.DEFAULT_PRECISION) { // the default is actually 0 in spec annotations.append(", precision=").append(column.getPrecision()); } if (column.getScale() != Column.DEFAULT_SCALE) { // default is actually 0 in spec annotations.append(", scale=").append(column.getScale()); } else if (column.getLength() != 255) { annotations.append(", length=").append(column.getLength()); } // TODO support secondary table annotations.append(")"); } }
private void assertColumnPrecisionAndScale( ConstrainedProperty constrainedProperty, int expectedPrecision, int expectedScale) { Column column = new Column(); GrailsDomainBinder.bindNumericColumnConstraints(column, constrainedProperty); assertEquals(expectedPrecision, column.getPrecision()); assertEquals(expectedScale, column.getScale()); }
public void testScaleProperty() { DefaultGrailsDomainConfiguration config = getDomainConfig( "class Widget {\n" + " Long id \n" + " Long version \n" + " Float width \n" + " Float height \n" + " static mapping = {\n" + " width scale: 7\n" + " }\n" + "}"); Table tableMapping = getTableMapping("widget", config); Column heightColumn = tableMapping.getColumn(new Column("height")); Column widthColumn = tableMapping.getColumn(new Column("width")); assertEquals(7, widthColumn.getScale()); assertEquals(Column.DEFAULT_SCALE, heightColumn.getScale()); }
/** * Called to apply column definitions from the referenced FK column to this column. * * @param column the referenced column. */ public void overrideFromReferencedColumnIfNecessary(org.hibernate.mapping.Column column) { if (getMappingColumn() != null) { // columnDefinition can also be specified using @JoinColumn, hence we have to check // whether it is set or not if (StringHelper.isEmpty(sqlType)) { sqlType = column.getSqlType(); getMappingColumn().setSqlType(sqlType); } // these properties can only be applied on the referenced column - we can just take them over getMappingColumn().setLength(column.getLength()); getMappingColumn().setPrecision(column.getPrecision()); getMappingColumn().setScale(column.getScale()); } }
/** used for mappedBy cases */ public void linkValueUsingAColumnCopy(Column column, SimpleValue value) { initMappingColumn( // column.getName(), column.getQuotedName(), null, column.getLength(), column.getPrecision(), column.getScale(), getMappingColumn().isNullable(), column.getSqlType(), getMappingColumn().isUnique(), false // We do copy no strategy here ); linkWithValue(value); }
public void linkValueUsingDefaultColumnNaming( Column referencedColumn, PersistentClass referencedEntity, SimpleValue value) { String logicalReferencedColumn = getBuildingContext() .getMetadataCollector() .getLogicalColumnName(referencedEntity.getTable(), referencedColumn.getQuotedName()); String columnName = buildDefaultColumnName(referencedEntity, logicalReferencedColumn); // yuk side effect on an implicit column setLogicalColumnName(columnName); setReferencedColumn(logicalReferencedColumn); initMappingColumn( columnName, null, referencedColumn.getLength(), referencedColumn.getPrecision(), referencedColumn.getScale(), getMappingColumn() != null ? getMappingColumn().isNullable() : false, referencedColumn.getSqlType(), getMappingColumn() != null ? getMappingColumn().isUnique() : false, false); linkWithValue(value); }
/** * Builds the <code>Join</code> instance for the mapped by side of a <i>OneToOne</i> association * using a join tables. * * <p>Note:<br> * * <ul> * <li>From the mappedBy side we should not create the PK nor the FK, this is handled from the * other side. * <li>This method is a dirty dupe of EntityBinder.bindSecondaryTable</i>. */ private Join buildJoinFromMappedBySide( PersistentClass persistentClass, Property otherSideProperty, Join originalJoin) { Join join = new Join(); join.setPersistentClass(persistentClass); // no check constraints available on joins join.setTable(originalJoin.getTable()); join.setInverse(true); SimpleValue key = new DependantValue(mappings, join.getTable(), persistentClass.getIdentifier()); // TODO support @ForeignKey join.setKey(key); join.setSequentialSelect(false); // TODO support for inverse and optional join.setOptional(true); // perhaps not quite per-spec, but a Good Thing anyway key.setCascadeDeleteEnabled(false); Iterator mappedByColumns = otherSideProperty.getValue().getColumnIterator(); while (mappedByColumns.hasNext()) { Column column = (Column) mappedByColumns.next(); Column copy = new Column(); copy.setLength(column.getLength()); copy.setScale(column.getScale()); copy.setValue(key); copy.setName(column.getQuotedName()); copy.setNullable(column.isNullable()); copy.setPrecision(column.getPrecision()); copy.setUnique(column.isUnique()); copy.setSqlType(column.getSqlType()); copy.setCheckConstraint(column.getCheckConstraint()); copy.setComment(column.getComment()); copy.setDefaultValue(column.getDefaultValue()); key.addColumn(copy); } persistentClass.addJoin(join); return join; }
/** * @param column * @param generatedIdentifier * @return */ private String guessAndAlignType( Table table, Column column, Mapping mapping, boolean generatedIdentifier) { // TODO: this method mutates the column if the types does not match...not good. // maybe we should copy the column instead before calling this method. Integer sqlTypeCode = column.getSqlTypeCode(); String location = "Table: " + Table.qualify(table.getCatalog(), table.getSchema(), table.getQuotedName()) + " column: " + column.getQuotedName(); if (sqlTypeCode == null) { throw new JDBCBinderException("sqltype is null for " + location); } String preferredHibernateType = revengStrategy.columnToHibernateTypeName( TableIdentifier.create(table), column.getName(), sqlTypeCode.intValue(), column.getLength(), column.getPrecision(), column.getScale(), column.isNullable(), generatedIdentifier); Type wantedType = TypeFactory.heuristicType(preferredHibernateType); if (wantedType != null) { int[] wantedSqlTypes = wantedType.sqlTypes(mapping); if (wantedSqlTypes.length > 1) { throw new JDBCBinderException( "The type " + preferredHibernateType + " found on " + location + " spans multiple columns. Only single column types allowed."); } int wantedSqlType = wantedSqlTypes[0]; if (wantedSqlType != sqlTypeCode.intValue()) { log.debug( "Sql type mismatch for " + location + " between DB and wanted hibernate type. Sql type set to " + typeCodeName(sqlTypeCode.intValue()) + " instead of " + typeCodeName(wantedSqlType)); column.setSqlTypeCode(new Integer(wantedSqlType)); } } else { log.debug( "No Hibernate type found for " + preferredHibernateType + ". Most likely cause is a missing UserType class."); } if (preferredHibernateType == null) { throw new JDBCBinderException( "Could not find javatype for " + typeCodeName(sqlTypeCode.intValue())); } return preferredHibernateType; }
// TODO refactor this code, there is a lot of duplication in this method public void doSecondPass(Map persistentClasses) throws MappingException { org.hibernate.mapping.OneToOne value = new org.hibernate.mapping.OneToOne( mappings, propertyHolder.getTable(), propertyHolder.getPersistentClass()); final String propertyName = inferredData.getPropertyName(); value.setPropertyName(propertyName); String referencedEntityName = ToOneBinder.getReferenceEntityName(inferredData, targetEntity, mappings); value.setReferencedEntityName(referencedEntityName); AnnotationBinder.defineFetchingStrategy(value, inferredData.getProperty()); // value.setFetchMode( fetchMode ); value.setCascadeDeleteEnabled(cascadeOnDelete); // value.setLazy( fetchMode != FetchMode.JOIN ); if (!optional) value.setConstrained(true); value.setForeignKeyType( value.isConstrained() ? ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT : ForeignKeyDirection.FOREIGN_KEY_TO_PARENT); PropertyBinder binder = new PropertyBinder(); binder.setName(propertyName); binder.setValue(value); binder.setCascade(cascadeStrategy); binder.setAccessType(inferredData.getDefaultAccess()); Property prop = binder.makeProperty(); if (BinderHelper.isEmptyAnnotationValue(mappedBy)) { /* * we need to check if the columns are in the right order * if not, then we need to create a many to one and formula * but actually, since entities linked by a one to one need * to share the same composite id class, this cannot happen in hibernate */ boolean rightOrder = true; if (rightOrder) { String path = StringHelper.qualify(propertyHolder.getPath(), propertyName); (new ToOneFkSecondPass( value, joinColumns, !optional, // cannot have nullabe and unique on certain DBs propertyHolder.getEntityOwnerClassName(), path, mappings)) .doSecondPass(persistentClasses); // no column associated since its a one to one propertyHolder.addProperty(prop, inferredData.getDeclaringClass()); } else { // this is a many to one with Formula } } else { PersistentClass otherSide = (PersistentClass) persistentClasses.get(value.getReferencedEntityName()); Property otherSideProperty; try { if (otherSide == null) { throw new MappingException("Unable to find entity: " + value.getReferencedEntityName()); } otherSideProperty = BinderHelper.findPropertyByName(otherSide, mappedBy); } catch (MappingException e) { throw new AnnotationException( "Unknown mappedBy in: " + StringHelper.qualify(ownerEntity, ownerProperty) + ", referenced property unknown: " + StringHelper.qualify(value.getReferencedEntityName(), mappedBy)); } if (otherSideProperty == null) { throw new AnnotationException( "Unknown mappedBy in: " + StringHelper.qualify(ownerEntity, ownerProperty) + ", referenced property unknown: " + StringHelper.qualify(value.getReferencedEntityName(), mappedBy)); } if (otherSideProperty.getValue() instanceof OneToOne) { propertyHolder.addProperty(prop, inferredData.getDeclaringClass()); } else if (otherSideProperty.getValue() instanceof ManyToOne) { Iterator it = otherSide.getJoinIterator(); Join otherSideJoin = null; while (it.hasNext()) { Join otherSideJoinValue = (Join) it.next(); if (otherSideJoinValue.containsProperty(otherSideProperty)) { otherSideJoin = otherSideJoinValue; break; } } if (otherSideJoin != null) { // @OneToOne @JoinTable Join mappedByJoin = buildJoinFromMappedBySide( (PersistentClass) persistentClasses.get(ownerEntity), otherSideProperty, otherSideJoin); ManyToOne manyToOne = new ManyToOne(mappings, mappedByJoin.getTable()); // FIXME use ignore not found here manyToOne.setIgnoreNotFound(ignoreNotFound); manyToOne.setCascadeDeleteEnabled(value.isCascadeDeleteEnabled()); manyToOne.setEmbedded(value.isEmbedded()); manyToOne.setFetchMode(value.getFetchMode()); manyToOne.setLazy(value.isLazy()); manyToOne.setReferencedEntityName(value.getReferencedEntityName()); manyToOne.setUnwrapProxy(value.isUnwrapProxy()); prop.setValue(manyToOne); Iterator otherSideJoinKeyColumns = otherSideJoin.getKey().getColumnIterator(); while (otherSideJoinKeyColumns.hasNext()) { Column column = (Column) otherSideJoinKeyColumns.next(); Column copy = new Column(); copy.setLength(column.getLength()); copy.setScale(column.getScale()); copy.setValue(manyToOne); copy.setName(column.getQuotedName()); copy.setNullable(column.isNullable()); copy.setPrecision(column.getPrecision()); copy.setUnique(column.isUnique()); copy.setSqlType(column.getSqlType()); copy.setCheckConstraint(column.getCheckConstraint()); copy.setComment(column.getComment()); copy.setDefaultValue(column.getDefaultValue()); manyToOne.addColumn(copy); } mappedByJoin.addProperty(prop); } else { propertyHolder.addProperty(prop, inferredData.getDeclaringClass()); } value.setReferencedPropertyName(mappedBy); String propertyRef = value.getReferencedPropertyName(); if (propertyRef != null) { mappings.addUniquePropertyReference(value.getReferencedEntityName(), propertyRef); } } else { throw new AnnotationException( "Referenced property not a (One|Many)ToOne: " + StringHelper.qualify(otherSide.getEntityName(), mappedBy) + " in mappedBy of " + StringHelper.qualify(ownerEntity, ownerProperty)); } } ForeignKey fk = inferredData.getProperty().getAnnotation(ForeignKey.class); String fkName = fk != null ? fk.name() : ""; if (!BinderHelper.isEmptyAnnotationValue(fkName)) value.setForeignKeyName(fkName); }