/** * Used by subclasses to resolve deferred values on demand. This is useful when a certain value * comes from a generated key of another master object. */ protected Object getValue(Map<String, Object> valueMap, DbAttribute attribute) { Object value = valueMap.get(attribute.getName()); // if a value is a Factory, resolve it here... // slight chance that a normal value will implement Factory interface??? if (value instanceof Factory) { value = ((Factory) value).create(); valueMap.put(attribute.getName(), value); // update replacement id if (attribute.isPrimaryKey()) { // sanity check if (value == null) { String name = attribute.getEntity() != null ? attribute.getEntity().getName() : "<null>"; throw new CayenneRuntimeException( "Failed to generate PK: " + name + "." + attribute.getName()); } ObjectId id = getObjectId(); if (id != null) { // always override with fresh value as this is what's in the // DB id.getReplacementIdMap().put(attribute.getName(), value); } } } return value; }
public List<String> createSql(DbEntity entity, DbAttribute column) { SQLParameterBinding value = get(entity, column); if (value == null) { return Collections.emptyList(); } // TODO: change things so it is possible to use prepared statements here return Collections.singletonList( "UPDATE " + entity.getFullyQualifiedName() + " SET " + column.getName() + "='" + value.getValue() + "' WHERE " + column.getName() + " IS NULL"); }
private String createKey(DbEntity entity, DbAttribute attribute) { return (entity.getFullyQualifiedName() + "." + attribute.getName()).toUpperCase(); }
/** * Customizes table creating procedure for PostgreSQL. One difference with generic implementation * is that "bytea" type has no explicit length unlike similar binary types in other databases. * * @since 1.0.2 */ @Override public String createTable(DbEntity ent) { boolean status; if (ent.getDataMap() != null && ent.getDataMap().isQuotingSQLIdentifiers()) { status = true; } else { status = false; } QuotingStrategy context = getQuotingStrategy(status); StringBuilder buf = new StringBuilder(); buf.append("CREATE TABLE "); buf.append(context.quoteFullyQualifiedName(ent)); buf.append(" ("); // columns Iterator<DbAttribute> it = ent.getAttributes().iterator(); boolean first = true; while (it.hasNext()) { if (first) first = false; else buf.append(", "); DbAttribute at = it.next(); // attribute may not be fully valid, do a simple check if (at.getType() == TypesMapping.NOT_DEFINED) { throw new CayenneRuntimeException( "Undefined type for attribute '" + ent.getFullyQualifiedName() + "." + at.getName() + "'."); } String[] types = externalTypesForJdbcType(at.getType()); if (types == null || types.length == 0) { throw new CayenneRuntimeException( "Undefined type for attribute '" + ent.getFullyQualifiedName() + "." + at.getName() + "': " + at.getType()); } String type = types[0]; buf.append(context.quoteString(at.getName())).append(' ').append(type); // append size and precision (if applicable) if (typeSupportsLength(at.getType())) { int len = at.getMaxLength(); int scale = (TypesMapping.isDecimal(at.getType()) && at.getType() != Types.FLOAT) // Postgress // don't // support // notations // float(a, // b) ? at.getScale() : -1; // sanity check if (scale > len) { scale = -1; } if (len > 0) { buf.append('(').append(len); if (scale >= 0) { buf.append(", ").append(scale); } buf.append(')'); } } if (at.isMandatory()) { buf.append(" NOT NULL"); } else { buf.append(" NULL"); } } // primary key clause Iterator<DbAttribute> pkit = ent.getPrimaryKeys().iterator(); if (pkit.hasNext()) { if (first) first = false; else buf.append(", "); buf.append("PRIMARY KEY ("); boolean firstPk = true; while (pkit.hasNext()) { if (firstPk) firstPk = false; else buf.append(", "); DbAttribute at = pkit.next(); buf.append(context.quoteString(at.getName())); } buf.append(')'); } buf.append(')'); return buf.toString(); }
public void testForeignKey() throws Exception { dropTableIfPresent("NEW_TABLE"); dropTableIfPresent("NEW_TABLE2"); assertTokensAndExecute(0, 0); DbEntity dbEntity1 = new DbEntity("NEW_TABLE"); DbAttribute e1col1 = new DbAttribute("ID", Types.INTEGER, dbEntity1); e1col1.setMandatory(true); e1col1.setPrimaryKey(true); dbEntity1.addAttribute(e1col1); DbAttribute e1col2 = new DbAttribute("NAME", Types.VARCHAR, dbEntity1); e1col2.setMaxLength(10); e1col2.setMandatory(false); dbEntity1.addAttribute(e1col2); map.addDbEntity(dbEntity1); DbEntity dbEntity2 = new DbEntity("NEW_TABLE2"); DbAttribute e2col1 = new DbAttribute("ID", Types.INTEGER, dbEntity2); e2col1.setMandatory(true); e2col1.setPrimaryKey(true); dbEntity2.addAttribute(e2col1); DbAttribute e2col2 = new DbAttribute("FK", Types.INTEGER, dbEntity2); dbEntity2.addAttribute(e2col2); DbAttribute e2col3 = new DbAttribute("NAME", Types.VARCHAR, dbEntity2); e2col3.setMaxLength(10); dbEntity2.addAttribute(e2col3); map.addDbEntity(dbEntity2); // create db relationships DbRelationship rel1To2 = new DbRelationship("rel1To2"); rel1To2.setSourceEntity(dbEntity1); rel1To2.setTargetEntity(dbEntity2); rel1To2.setToMany(true); rel1To2.addJoin(new DbJoin(rel1To2, e1col1.getName(), e2col2.getName())); dbEntity1.addRelationship(rel1To2); DbRelationship rel2To1 = new DbRelationship("rel2To1"); rel2To1.setSourceEntity(dbEntity2); rel2To1.setTargetEntity(dbEntity1); rel2To1.setToMany(false); rel2To1.addJoin(new DbJoin(rel2To1, e2col2.getName(), e1col1.getName())); dbEntity2.addRelationship(rel2To1); assertSame(rel1To2, rel2To1.getReverseRelationship()); assertSame(rel2To1, rel1To2.getReverseRelationship()); assertTokensAndExecute(4, 0); assertTokensAndExecute(0, 0); // create ObjEntities ObjEntity objEntity1 = new ObjEntity("NewTable"); objEntity1.setDbEntity(dbEntity1); ObjAttribute oatr1 = new ObjAttribute("name"); oatr1.setDbAttributePath(e1col2.getName()); oatr1.setType("java.lang.String"); objEntity1.addAttribute(oatr1); map.addObjEntity(objEntity1); ObjEntity objEntity2 = new ObjEntity("NewTable2"); objEntity2.setDbEntity(dbEntity2); ObjAttribute o2a1 = new ObjAttribute("name"); o2a1.setDbAttributePath(e2col3.getName()); o2a1.setType("java.lang.String"); objEntity2.addAttribute(o2a1); map.addObjEntity(objEntity2); // create ObjRelationships assertEquals(0, objEntity1.getRelationships().size()); assertEquals(0, objEntity2.getRelationships().size()); ObjRelationship objRel1To2 = new ObjRelationship("objRel1To2"); objRel1To2.addDbRelationship(rel1To2); objRel1To2.setSourceEntity(objEntity1); objRel1To2.setTargetEntity(objEntity2); objEntity1.addRelationship(objRel1To2); ObjRelationship objRel2To1 = new ObjRelationship("objRel2To1"); objRel2To1.addDbRelationship(rel2To1); objRel2To1.setSourceEntity(objEntity2); objRel2To1.setTargetEntity(objEntity1); objEntity2.addRelationship(objRel2To1); assertEquals(1, objEntity1.getRelationships().size()); assertEquals(1, objEntity2.getRelationships().size()); assertSame(objRel1To2, objRel2To1.getReverseRelationship()); assertSame(objRel2To1, objRel1To2.getReverseRelationship()); // remove relationship and fk from model, merge to db and read to model dbEntity2.removeRelationship(rel2To1.getName()); dbEntity1.removeRelationship(rel1To2.getName()); dbEntity2.removeAttribute(e2col2.getName()); List<MergerToken> tokens = createMergeTokens(); assertTokens(tokens, 2, 1); for (MergerToken token : tokens) { if (token.getDirection().isToDb()) { execute(token); } } assertTokensAndExecute(0, 0); dbEntity2.addRelationship(rel2To1); dbEntity1.addRelationship(rel1To2); dbEntity2.addAttribute(e2col2); // try do use the merger to remove the relationship in the model tokens = createMergeTokens(); assertTokens(tokens, 2, 0); // TODO: reversing the following two tokens should also reverse the order MergerToken token0 = tokens.get(0).createReverse(mergerFactory()); MergerToken token1 = tokens.get(1).createReverse(mergerFactory()); if (!(token0 instanceof DropRelationshipToModel && token1 instanceof DropColumnToModel || token1 instanceof DropRelationshipToModel && token0 instanceof DropColumnToModel)) { fail(); } execute(token0); execute(token1); // check after merging assertNull(dbEntity2.getAttribute(e2col2.getName())); assertEquals(0, dbEntity1.getRelationships().size()); assertEquals(0, dbEntity2.getRelationships().size()); assertEquals(0, objEntity1.getRelationships().size()); assertEquals(0, objEntity2.getRelationships().size()); // clear up dbEntity1.removeRelationship(rel1To2.getName()); dbEntity2.removeRelationship(rel2To1.getName()); map.removeObjEntity(objEntity1.getName(), true); map.removeDbEntity(dbEntity1.getName(), true); map.removeObjEntity(objEntity2.getName(), true); map.removeDbEntity(dbEntity2.getName(), true); resolver.refreshMappingCache(); assertNull(map.getObjEntity(objEntity1.getName())); assertNull(map.getDbEntity(dbEntity1.getName())); assertNull(map.getObjEntity(objEntity2.getName())); assertNull(map.getDbEntity(dbEntity2.getName())); assertFalse(map.getDbEntities().contains(dbEntity1)); assertFalse(map.getDbEntities().contains(dbEntity2)); assertTokensAndExecute(2, 0); assertTokensAndExecute(0, 0); }