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 <61057136+bj...@users.noreply.github.com>
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>

Reply via email to