This is an automated email from the ASF dual-hosted git repository.
jleroux pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new e786da4 Fixed: Induction from DB does not represent relations
properly. (#290) (OFBIZ-12178)
e786da4 is described below
commit e786da42e852fbf4723dc0b9680e432ea24b61a8
Author: bjugl <[email protected]>
AuthorDate: Fri Apr 2 11:12:42 2021 +0200
Fixed: Induction from DB does not represent relations properly. (#290)
(OFBIZ-12178)
As encountered in OFBIZ-6510, the ModelInduceFromDb does currently not
include entity relations and foreign key constraints. Since they are an
important part of the database model, we should fix that.
I could track down the problem to an incomplete invocation of the
ModelEntity through the constructor used in the
DatabaseUtil.induceModelFromDb() Methods. This constructor does not initialize
the Relations.
Problem is, that the ModelEntity initialized through the "DB Names
Constructor" does not cover references in its current state at all.
While working on an implementation I realized, that the API is not very
congruent in this regards. I would expect that I could initialize
ModelRelations the same way ModelFields are initialized in this context:
The create() Method takes a ModelEntity, DatabaseUtil.ColumnCheckInfo
(respectively a DatabaseUtil.ReferenceCheckInfo) and a ModelFieldTypeReader
(that could be left out for references) and creates ModelField (ModelRelation)
objects that are added to the ModelEntity.
But that is not the case at the moment. On one hand not all fields that
would be necessary are covered in the DatabaseUtil.ReferenceCheckInfo Objects
(e.g. "type" is missing), on the other the object is missing public getters to
make the values available in the first place.
Thanks a bunch Benjamin, nice add !
---
.../org/apache/ofbiz/entity/jdbc/DatabaseUtil.java | 260 ++++++++++++++-------
.../org/apache/ofbiz/entity/model/ModelEntity.java | 27 +++
.../apache/ofbiz/entity/model/ModelRelation.java | 66 +++---
framework/webtools/config/WebtoolsUiLabels.xml | 8 +
.../webtools/template/entity/ModelInduceFromDb.ftl | 3 +
5 files changed, 254 insertions(+), 110 deletions(-)
diff --git
a/framework/entity/src/main/java/org/apache/ofbiz/entity/jdbc/DatabaseUtil.java
b/framework/entity/src/main/java/org/apache/ofbiz/entity/jdbc/DatabaseUtil.java
index 5f2fcb5..531d723 100644
---
a/framework/entity/src/main/java/org/apache/ofbiz/entity/jdbc/DatabaseUtil.java
+++
b/framework/entity/src/main/java/org/apache/ofbiz/entity/jdbc/DatabaseUtil.java
@@ -44,6 +44,7 @@ import java.util.concurrent.Future;
import org.apache.ofbiz.base.concurrent.ExecutionPool;
import org.apache.ofbiz.base.util.Debug;
+import org.apache.ofbiz.base.util.StringUtil;
import org.apache.ofbiz.base.util.UtilTimer;
import org.apache.ofbiz.base.util.UtilValidate;
import org.apache.ofbiz.entity.GenericEntityException;
@@ -57,6 +58,7 @@ import org.apache.ofbiz.entity.model.ModelFieldTypeReader;
import org.apache.ofbiz.entity.model.ModelIndex;
import org.apache.ofbiz.entity.model.ModelKeyMap;
import org.apache.ofbiz.entity.model.ModelRelation;
+import org.apache.ofbiz.entity.model.ModelUtil;
import org.apache.ofbiz.entity.model.ModelViewEntity;
import org.apache.ofbiz.entity.transaction.TransactionFactoryLoader;
import org.apache.ofbiz.entity.transaction.TransactionUtil;
@@ -861,6 +863,7 @@ public class DatabaseUtil {
if (UtilValidate.isNotEmpty(tableNames)) {
// get ALL column info, put into hashmap by table name
Map<String, Map<String, ColumnCheckInfo>> colInfo =
getColumnInfo(tableNames, true, messages, executor);
+ Map<String, Map<String, ReferenceCheckInfo>> refInfo =
getReferenceInfo(tableNames, messages);
// go through each table and make a ModelEntity object, add to list
// for each entity make corresponding ModelField objects
// then print out XML for the entities/fields
@@ -868,7 +871,8 @@ public class DatabaseUtil {
// iterate over the table names is alphabetical order
for (String tableName : new TreeSet<>(colInfo.keySet())) {
Map<String, ColumnCheckInfo> colMap = colInfo.get(tableName);
- ModelEntity newEntity = new ModelEntity(tableName, colMap,
modelFieldTypeReader, isCaseSensitive);
+ Map<String, ReferenceCheckInfo> refMap =
refInfo.get(tableName);
+ ModelEntity newEntity = new ModelEntity(tableName, colMap,
refMap, modelFieldTypeReader, isCaseSensitive);
newEntList.add(newEntity);
}
}
@@ -1328,7 +1332,11 @@ public class DatabaseUtil {
* @param messages the messages
* @return the reference info
*/
- public Map<String, Map<String, ReferenceCheckInfo>>
getReferenceInfo(Set<String> tableNames, Collection<String> messages) {
+ public Map<String, Map<String, ReferenceCheckInfo>>
getReferenceInfo(Set<String> tableNames,
+ Collection<String> messages) {
+ if (UtilValidate.isEmpty(tableNames)) {
+ return new HashMap<>();
+ }
Connection connection = getConnectionLogged(messages);
if (connection == null) {
return null;
@@ -1340,41 +1348,46 @@ public class DatabaseUtil {
} catch (SQLException e) {
String message = "Unable to get database meta data... Error was:"
+ e.toString();
Debug.logError(message, MODULE);
- if (messages != null) messages.add(message);
+ if (messages != null) {
+ messages.add(message);
+ }
try {
connection.close();
} catch (SQLException e2) {
- String message2 = "Unable to close database connection,
continuing anyway... Error was:" + e2.toString();
+ String message2 = "Unable to close database connection,
continuing anyway... Error was:" + e2
+ .toString();
Debug.logError(message2, MODULE);
- if (messages != null) messages.add(message2);
+ if (messages != null) {
+ messages.add(message2);
+ }
}
return null;
}
/*
- try {
- if (Debug.infoOn()) Debug.logInfo("Database Product Name is " +
dbData.getDatabaseProductName(), MODULE);
- if (Debug.infoOn()) Debug.logInfo("Database Product Version is " +
dbData.getDatabaseProductVersion(), MODULE);
- } catch (SQLException e) {
- Debug.logWarning("Unable to get Database name & version information",
MODULE);
- }
- try {
- if (Debug.infoOn()) Debug.logInfo("Database Driver Name is " +
dbData.getDriverName(), MODULE);
- if (Debug.infoOn()) Debug.logInfo("Database Driver Version is " +
dbData.getDriverVersion(), MODULE);
- } catch (SQLException e) {
- Debug.logWarning("Unable to get Driver name & version information",
MODULE);
- }
+ * try { if (Debug.infoOn()) Debug.logInfo("Database Product Name is "
+
+ * dbData.getDatabaseProductName(), MODULE); if (Debug.infoOn())
+ * Debug.logInfo("Database Product Version is " +
+ * dbData.getDatabaseProductVersion(), MODULE); } catch (SQLException
e) {
+ * Debug.logWarning("Unable to get Database name & version
information",
+ * MODULE); } try { if (Debug.infoOn()) Debug.logInfo("Database Driver
Name is "
+ * + dbData.getDriverName(), MODULE); if (Debug.infoOn())
+ * Debug.logInfo("Database Driver Version is " +
dbData.getDriverVersion(),
+ * MODULE); } catch (SQLException e) {
+ * Debug.logWarning("Unable to get Driver name & version information",
MODULE);
+ * }
*/
if (Debug.infoOn()) {
Debug.logInfo("Getting Foreign Key (Reference) Info From
Database", MODULE);
}
- Map<String, Map<String, ReferenceCheckInfo>> refInfo = new HashMap<>();
+ Map<String, Map<String, ReferenceCheckInfo>> retMap = new HashMap<>();
try {
- // ResultSet rsCols = dbData.getCrossReference(null, null, null,
null, null, null);
+ // ResultSet rsCols = dbData.getCrossReference(null, null, null,
null, null,
+ // null);
String lookupSchemaName = getSchemaName(dbData);
boolean needsUpperCase = false;
try {
@@ -1382,99 +1395,110 @@ public class DatabaseUtil {
} catch (SQLException e) {
String message = "Error getting identifier case information...
Error was:" + e.toString();
Debug.logError(message, MODULE);
- if (messages != null) messages.add(message);
+ if (messages != null) {
+ messages.add(message);
+ }
}
- ResultSet rsCols = dbData.getImportedKeys(null, lookupSchemaName,
null);
int totalFkRefs = 0;
- // Iterator tableNamesIter = tableNames.iterator();
- // while (tableNamesIter.hasNext()) {
- // String tableName = (String) tableNamesIter.next();
- // ResultSet rsCols = dbData.getImportedKeys(null, null,
tableName);
- // Debug.logVerbose("Getting imported keys for table " +
tableName, MODULE);
+ for (String tableName : tableNames) {
+ String shortTableName = tableName.split("\\.").length > 0 ?
tableName.split("\\.")[tableName.split(
+ "\\.").length - 1] : tableName;
+ ResultSet rsCols = dbData.getImportedKeys(null,
lookupSchemaName, shortTableName);
+ // ResultSetMetaData rsMeta = rsCols.getMetaData();
- while (rsCols.next()) {
- try {
- ReferenceCheckInfo rcInfo = new ReferenceCheckInfo();
+ Map<String, ReferenceCheckInfo> tableRefInfo =
retMap.get(tableName);
+ if (tableRefInfo == null) {
+ tableRefInfo = new HashMap<>();
+ totalFkRefs++;
+ }
+ while (rsCols.next()) {
+ try {
+ String fkName = toUpper(rsCols.getString("FK_NAME"),
needsUpperCase);
+ int seq = rsCols.getInt("KEY_SEQ");
+ String fkTableName =
toUpper(rsCols.getString("FKTABLE_NAME"), needsUpperCase);
+ String fkColumnName =
toUpper(rsCols.getString("FKCOLUMN_NAME"), needsUpperCase);
+ String pkTableName =
toUpper(rsCols.getString("PKTABLE_NAME"), needsUpperCase);
+ String pkColumnName =
toUpper(rsCols.getString("PKCOLUMN_NAME"), needsUpperCase);
- rcInfo.pkTableName = rsCols.getString("PKTABLE_NAME");
- if (needsUpperCase && rcInfo.pkTableName != null) {
- rcInfo.pkTableName = rcInfo.pkTableName.toUpperCase();
- }
- rcInfo.pkColumnName = rsCols.getString("PKCOLUMN_NAME");
- if (needsUpperCase && rcInfo.pkColumnName != null) {
- rcInfo.pkColumnName =
rcInfo.pkColumnName.toUpperCase();
- }
+ ReferenceCheckInfo rcInfo = tableRefInfo.get(fkName);
+ if (rcInfo == null) {
+ rcInfo = new ReferenceCheckInfo();
- rcInfo.fkTableName = rsCols.getString("FKTABLE_NAME");
- if (needsUpperCase && rcInfo.fkTableName != null) {
- rcInfo.fkTableName = rcInfo.fkTableName.toUpperCase();
- }
- // ignore the column info if the FK table name is not in
the list we are concerned with
- if (!tableNames.contains(rcInfo.fkTableName)) {
- continue;
- }
- rcInfo.fkColumnName = rsCols.getString("FKCOLUMN_NAME");
- if (needsUpperCase && rcInfo.fkColumnName != null) {
- rcInfo.fkColumnName =
rcInfo.fkColumnName.toUpperCase();
- }
- rcInfo.fkName = rsCols.getString("FK_NAME");
- if (needsUpperCase && rcInfo.fkName != null) {
- rcInfo.fkName = rcInfo.fkName.toUpperCase();
- }
+ }
- if (Debug.verboseOn()) {
- Debug.logVerbose("Got: " + rcInfo.toString(), MODULE);
- }
+ rcInfo.fkName = fkName;
+ rcInfo.fkTableName = fkTableName;
+ rcInfo.pkTableName = pkTableName;
+
+ if (seq > 1) {
+ rcInfo.pkColumnName =
rcInfo.pkColumnName.concat(",").concat(pkColumnName);
+ rcInfo.fkColumnName =
rcInfo.fkColumnName.concat(",").concat(fkColumnName);
+ } else {
+ rcInfo.pkColumnName = pkColumnName;
+ rcInfo.fkColumnName = fkColumnName;
+ }
- Map<String, ReferenceCheckInfo> tableRefInfo =
refInfo.get(rcInfo.fkTableName);
- if (tableRefInfo == null) {
- tableRefInfo = new HashMap<>();
- refInfo.put(rcInfo.fkTableName, tableRefInfo);
if (Debug.verboseOn()) {
- Debug.logVerbose("Adding new Map for table: " +
rcInfo.fkTableName, MODULE);
+ Debug.logVerbose("Got: " + rcInfo.toString(),
MODULE);
+ }
+ tableRefInfo.put(fkName, rcInfo);
+ retMap.put(tableName, tableRefInfo);
+ } catch (SQLException e) {
+ String message = "Error getting fk reference info for
table. Error was:" + e.toString();
+ Debug.logError(message, MODULE);
+ if (messages != null) {
+ messages.add(message);
}
+ continue;
}
- if (!tableRefInfo.containsKey(rcInfo.fkName))
totalFkRefs++;
- tableRefInfo.put(rcInfo.fkName, rcInfo);
+ }
+ // if (Debug.infoOn()) {
+ // Debug.logInfo("There are " + totalFkRefs + " in the
database", MODULE)
+ // };
+ try {
+ rsCols.close();
} catch (SQLException e) {
- String message = "Error getting fk reference info for
table. Error was:" + e.toString();
+ String message = "Unable to close ResultSet for fk
reference list, continuing anyway... Error was:"
+ + e.toString();
Debug.logError(message, MODULE);
- if (messages != null) messages.add(message);
- continue;
+ if (messages != null) {
+ messages.add(message);
+ }
}
}
-
- // if (Debug.infoOn()) {
- // Debug.logInfo("There are " + totalFkRefs + " in the database",
MODULE)
- // };
- try {
- rsCols.close();
- } catch (SQLException e) {
- String message = "Unable to close ResultSet for fk reference
list, continuing anyway... Error was:" + e.toString();
- Debug.logError(message, MODULE);
- if (messages != null) messages.add(message);
- }
if (Debug.infoOn()) {
Debug.logInfo("There are " + totalFkRefs + " foreign key refs
in the database", MODULE);
}
} catch (SQLException e) {
- String message = "Error getting fk reference meta data Error was:"
+ e.toString() + ". Not checking fk refs.";
+ String message = "Error getting fk reference meta data Error was:"
+ e.toString()
+ + ". Not checking fk refs.";
Debug.logError(message, MODULE);
- if (messages != null) messages.add(message);
- refInfo = null;
+ if (messages != null) {
+ messages.add(message);
+ }
+ retMap = null;
} finally {
try {
connection.close();
} catch (SQLException e) {
String message = "Unable to close database connection,
continuing anyway... Error was:" + e.toString();
Debug.logError(message, MODULE);
- if (messages != null) messages.add(message);
+ if (messages != null) {
+ messages.add(message);
+ }
}
}
- return refInfo;
+ return retMap;
+ }
+
+ private String toUpper(String string, boolean needsUpperCase) {
+ if (needsUpperCase && string != null) {
+ string = string.toUpperCase();
+ }
+ return string;
}
/**
@@ -3230,9 +3254,79 @@ public class DatabaseUtil {
*/
private String fkColumnName;
+ /**
+ * Gets pk table name
+ * @return the pk table name
+ */
+ public String getPkTableName() {
+ return pkTableName;
+ }
+
+ /**
+ * Gets pk column name
+ * @return the pk column name
+ */
+ public String getPkColumnName() {
+ return pkColumnName;
+ }
+
+ /**
+ * Gets fk name
+ * @return the fk name
+ */
+ public String getFkName() {
+ return fkName;
+ }
+
+ /**
+ * Gets fk table name
+ * @return the fk table name
+ */
+ public String getFkTableName() {
+ return fkTableName;
+ }
+
+ /**
+ * Gets fk column name
+ * @return the fk column name
+ */
+ public String getFkColumnName() {
+ return fkColumnName;
+ }
+
@Override
public String toString() {
- return "FK Reference from table " + fkTableName + " called " +
fkName + " to PK in table " + pkTableName;
+ StringBuilder ret = new StringBuilder();
+ ret.append("FK Reference from table ");
+ ret.append(fkTableName);
+ ret.append(" called ");
+ ret.append(fkName);
+ ret.append(" to PK in table ");
+ ret.append(pkTableName);
+ return ret.toString();
+ }
+
+ /**
+ * Converts the column information into ModelKeyMaps
+ * @return a list of ModelKeyMaps
+ */
+ public List<ModelKeyMap> toModelKeyMapList() {
+ List<ModelKeyMap> keyMaps = new ArrayList<>();
+
+ List<String> fieldNames = StringUtil.split(fkColumnName, ",");
+ List<String> relFieldNames = StringUtil.split(pkColumnName, ",");
+ if (fieldNames.size() != relFieldNames.size()) {
+ Debug.logError("Count of related fields for relation does not
match!", MODULE);
+ return null;
+ }
+ for (int i = 0; i < fieldNames.size(); i++) {
+ String fieldName =
ModelUtil.dbNameToVarName(fieldNames.get(i));
+ String relFieldName =
ModelUtil.dbNameToVarName(relFieldNames.get(i));
+ ModelKeyMap keyMap = new ModelKeyMap(fieldName, relFieldName);
+ keyMaps.add(keyMap);
+ }
+
+ return keyMaps;
}
}
diff --git
a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelEntity.java
b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelEntity.java
index 83e44e7..c7b8fe6 100644
---
a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelEntity.java
+++
b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelEntity.java
@@ -247,6 +247,33 @@ public class ModelEntity implements
Comparable<ModelEntity>, Serializable {
}
}
+ public ModelEntity(String tableName, Map<String,
DatabaseUtil.ColumnCheckInfo> colMap,
+ Map<String, DatabaseUtil.ReferenceCheckInfo> refMap,
ModelFieldTypeReader modelFieldTypeReader,
+ boolean isCaseSensitive) {
+ // if there is a dot in the name, remove it and everything before it,
should be
+ // the schema name
+ this.modelReader = null;
+ this.modelInfo = ModelInfo.DEFAULT;
+ this.tableName = tableName;
+ int dotIndex = this.tableName.indexOf('.');
+ if (dotIndex >= 0) {
+ this.tableName = this.tableName.substring(dotIndex + 1);
+ }
+ this.entityName = ModelUtil.dbNameToClassName(this.tableName);
+ for (Map.Entry<String, DatabaseUtil.ColumnCheckInfo> columnEntry :
colMap.entrySet()) {
+ DatabaseUtil.ColumnCheckInfo ccInfo = columnEntry.getValue();
+ ModelField newField = ModelField.create(this, ccInfo,
modelFieldTypeReader);
+ addField(newField);
+ }
+ if (UtilValidate.isNotEmpty(refMap)) {
+ for (Map.Entry<String, DatabaseUtil.ReferenceCheckInfo>
referenceEntry : refMap.entrySet()) {
+ DatabaseUtil.ReferenceCheckInfo rcInfo =
referenceEntry.getValue();
+ ModelRelation newRel = ModelRelation.create(this, rcInfo,
false);
+ addRelation(newRel);
+ }
+ }
+ }
+
/**
* Populate basic info.
* @param entityElement the entity element
diff --git
a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelRelation.java
b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelRelation.java
index ba429b5..9c0d5aa 100644
---
a/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelRelation.java
+++
b/framework/entity/src/main/java/org/apache/ofbiz/entity/model/ModelRelation.java
@@ -28,6 +28,7 @@ import java.util.TreeSet;
import org.apache.ofbiz.base.lang.ThreadSafe;
import org.apache.ofbiz.base.util.UtilValidate;
import org.apache.ofbiz.base.util.UtilXml;
+import org.apache.ofbiz.entity.jdbc.DatabaseUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -39,6 +40,34 @@ import org.w3c.dom.Element;
@SuppressWarnings("serial")
public final class ModelRelation extends ModelChild {
+ /*
+ * Developers - this is an immutable class. Once constructed, the object
should not change state.
+ * Therefore, 'setter' methods are not allowed. If client code needs to
modify the object's
+ * state, then it can create a new copy with the changed values.
+ */
+
+ /** the title, gives a name/description to the relation */
+ private final String title;
+
+ /** the type: either "one" or "many" or "one-nofk" */
+ private final String type;
+
+ /** the name of the related entity */
+ private final String relEntityName;
+
+ /** the name to use for a database foreign key, if applies */
+ private final String fkName;
+
+ /** keyMaps defining how to lookup the relatedTable using columns from
this table */
+ private final List<ModelKeyMap> keyMaps;
+
+ private final boolean isAutoRelation;
+
+ /** A String to uniquely identify this relation. */
+ private final String fullName;
+
+ private final String combinedName;
+
/**
* Returns a new <code>ModelRelation</code> instance, initialized with the
specified values.
* @param modelEntity The <code>ModelEntity</code> this relation is a
member of.
@@ -99,33 +128,16 @@ public final class ModelRelation extends ModelChild {
return new ModelRelation(modelEntity, description, type, title,
relEntityName, fkName, keyMaps, isAutoRelation);
}
- /*
- * Developers - this is an immutable class. Once constructed, the object
should not change state.
- * Therefore, 'setter' methods are not allowed. If client code needs to
modify the object's
- * state, then it can create a new copy with the changed values.
- */
-
- /** the title, gives a name/description to the relation */
- private final String title;
-
- /** the type: either "one" or "many" or "one-nofk" */
- private final String type;
-
- /** the name of the related entity */
- private final String relEntityName;
+ public static ModelRelation create(ModelEntity modelEntity,
DatabaseUtil.ReferenceCheckInfo refInfo, boolean isAutoRelation) {
+ String fkName = refInfo.getFkName();
+ String title = null;
+ String type = null;
+ String description = null;
+ String relEntityName =
ModelUtil.dbNameToClassName(refInfo.getPkTableName());
+ List<ModelKeyMap> keyMaps = refInfo.toModelKeyMapList();
- /** the name to use for a database foreign key, if applies */
- private final String fkName;
-
- /** keyMaps defining how to lookup the relatedTable using columns from
this table */
- private final List<ModelKeyMap> keyMaps;
-
- private final boolean isAutoRelation;
-
- /** A String to uniquely identify this relation. */
- private final String fullName;
-
- private final String combinedName;
+ return new ModelRelation(modelEntity, description, type, title,
relEntityName, fkName, keyMaps, isAutoRelation);
+ }
private ModelRelation(ModelEntity modelEntity, String description, String
type, String title, String relEntityName, String fkName,
List<ModelKeyMap> keyMaps, boolean isAutoRelation) {
@@ -149,7 +161,7 @@ public final class ModelRelation extends ModelChild {
}
sb.append("]");
this.fullName = sb.toString();
- this.combinedName = title.concat(relEntityName);
+ this.combinedName = title != null ? title.concat(relEntityName) :
relEntityName;
}
/** Returns the combined name (title + related entity name). */
diff --git a/framework/webtools/config/WebtoolsUiLabels.xml
b/framework/webtools/config/WebtoolsUiLabels.xml
index 863e2c5..22f7d85 100644
--- a/framework/webtools/config/WebtoolsUiLabels.xml
+++ b/framework/webtools/config/WebtoolsUiLabels.xml
@@ -6041,4 +6041,12 @@
<value xml:lang="de">Ermittlung der Datenstruktur fehlgeschlagen.
Bitte gültige Datenquelle angeben.</value>
<value xml:lang="en">Could not determine Structure for this
datasource. Please choose a valid datasource.</value>
</property>
+ <property key="typeAndTitleDisclaimer">
+ <value xml:lang="de">Bitte beachten Sie, dass die Attribute Type und
Title der Referenzen nicht aus der Datenbank heraus rekonstruiert werden
können.</value>
+ <value xml:lang="en">Please note that the attributes Type and Title
for references cannot be derived from the database.</value>
+ </property>
+ <property key="pleaseAddManually">
+ <value xml:lang="de">Diese müssen händisch nachgepflegt werden.</value>
+ <value xml:lang="en">These must be added manually.</value>
+ </property>
</resource>
diff --git a/framework/webtools/template/entity/ModelInduceFromDb.ftl
b/framework/webtools/template/entity/ModelInduceFromDb.ftl
index bb40ce6..c0c5ca1 100644
--- a/framework/webtools/template/entity/ModelInduceFromDb.ftl
+++ b/framework/webtools/template/entity/ModelInduceFromDb.ftl
@@ -54,6 +54,9 @@ under the License.
</table>
</form>
</hr>
+<div>${uiLabelMap.typeAndTitleDisclaimer}</div>
+<div>${uiLabelMap.pleaseAddManually}</div>
+</hr>
<div>
<textarea cols="60" rows="50"
name="${uiLabelMap.ModelInduceInducedText}">${inducedText!}</textarea>
</div>