Author: kaiyi4
Date: Wed Aug 27 13:51:06 2008
New Revision: 2635
Added:
trunk/src/ca/sqlpower/architect/swingui/olap/DimensionUsageEditPanel.java
Modified:
trunk/src/ca/sqlpower/architect/olap/OLAPUtil.java
trunk/src/ca/sqlpower/architect/swingui/olap/CubePane.java
trunk/src/ca/sqlpower/architect/swingui/olap/HierarchyEditPanel.java
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateDimensionUsageAction.java
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateHierarchyAction.java
Log:
New edit panel for dimensionUsage. When a dimUsage is created, its foreign
key will be set, and the referring dimension's foreign key is also set.
Also erased out hierarchy primary key setting property introduced in the
last commit.
Modified: trunk/src/ca/sqlpower/architect/olap/OLAPUtil.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/olap/OLAPUtil.java (original)
+++ trunk/src/ca/sqlpower/architect/olap/OLAPUtil.java Wed Aug 27 13:51:06
2008
@@ -57,17 +57,18 @@
}
/**
- * Finds the OLAPSession that owns the given OLAPObject, by following
- * parent pointers successively until an ancestor of type OLAPSession
- * is encountered. If there is no OLAPSession ancestor, returns null.
+ * Finds the OLAPSession that owns the given OLAPObject, by following
parent
+ * pointers successively until an ancestor of type OLAPSession is
+ * encountered. If there is no OLAPSession ancestor, returns null.
* <p>
* Note that when we say <i>ancestor</i> in this doc comment, we
include
- * the given <code>oo</code> object as an "ancestor" of itself. In
other
+ * the given <code>oo</code> object as an "ancestor" of itself. In
other
* words, if you pass in an OLAPSession, you will get that same object
back.
*
- * @param oo The object to start searching at
- * @return The nearest ancestor of type OLAPObject, or null if there is
- * no such ancestor.
+ * @param oo
+ * The object to start searching at
+ * @return The nearest ancestor of type OLAPObject, or null if there
is no
+ * such ancestor.
*/
public static OLAPSession getSession(OLAPObject oo) {
while (oo != null && !(oo instanceof OLAPSession)) {
@@ -78,8 +79,8 @@
/**
* Mondrian uses a single string as a table name qualifier, so this
method
- * helps by finding the parent schema and/or catalog and produces the
correct
- * Mondrian qualifier for the given table.
+ * helps by finding the parent schema and/or catalog and produces the
+ * correct Mondrian qualifier for the given table.
*/
public static String getQualifier(SQLTable t) {
SQLSchema schema = t.getSchema();
@@ -94,7 +95,7 @@
return catalog.getName() + "." + schema.getName();
}
}
-
+
/**
* Adds the given OLAPChildListener and optional
PropertyChangeListener to
* the given root object and all of its descendants.
@@ -133,9 +134,9 @@
* OLAPObjects rooted at root. It is not an error if the
listener
* is not registered with any or all of the objects in the
* subtree, so it's safe to call this with the root of the
tree
- * if you want. If you weren't listening for property
change events,
- * you can leave this parameter as null. Note that this
parameter
- * is pronounced "pockle," not "pickle."
+ * if you want. If you weren't listening for property change
+ * events, you can leave this parameter as null. Note that
this
+ * parameter is pronounced "pockle," not "pickle."
*/
public static void unlistenToHierarchy(OLAPObject root,
OLAPChildListener ocl, PropertyChangeListener pcl) {
root.removeChildListener(ocl);
@@ -146,7 +147,7 @@
unlistenToHierarchy(child, ocl, pcl);
}
}
-
+
/**
* [EMAIL PROTECTED] OLAPObject#getName()} does not always return the correct
name so
* this method helps by finding the proper name for those exceptions
and
@@ -158,8 +159,9 @@
* @return The name of the given object, null if the object is null
itself.
*/
public static String nameFor(OLAPObject obj) {
- if (obj == null) return null;
-
+ if (obj == null)
+ return null;
+
if (obj instanceof CubeUsage) {
return ((CubeUsage) obj).getCubeName();
} else if (obj instanceof Hierarchy) {
@@ -190,15 +192,17 @@
OLAPSession session = getSession(hier);
SQLDatabase database = session.getDatabase();
RelationOrJoin relation = hier.getRelation();
-
- // If this hierarchy belongs to a shared dimension, its relation
is all we can get.
- // But if this hierarchy belongs to a private dimension, its
cube's fact specifies
+
+ // If this hierarchy belongs to a shared dimension, its relation
is all
+ // we can get.
+ // But if this hierarchy belongs to a private dimension, its
cube's fact
+ // specifies
// the default table.
if (relation == null && hier.getParent().getParent() instanceof
Cube) {
Cube owningCube = (Cube) hier.getParent().getParent();
relation = owningCube.getFact();
}
-
+
return tableForRelationOrJoin(database, relation);
}
@@ -234,22 +238,7 @@
if (relation == null) {
return null;
} else if (relation instanceof Table) {
- Table table = (Table) relation;
- String qualifier = table.getSchema();
- String name = table.getName();
- if (qualifier == null || qualifier.length() == 0) {
- return (SQLTable) database.getChildByName(name);
- } else if (qualifier.contains(".")) {
- String cat = qualifier.substring(0,
qualifier.indexOf('.'));
- String schema = qualifier.substring(qualifier.indexOf('.')
+ 1);
- return database.getTableByName(cat, schema, name);
- } else if (ArchitectUtils.isCompatibleWithHierarchy(database,
qualifier, null, name)) {
- return database.getTableByName(qualifier, null, name);
- } else if (ArchitectUtils.isCompatibleWithHierarchy(database,
null, qualifier, name)) {
- return database.getTableByName(null, qualifier, name);
- } else {
- return null;
- }
+ return getSQLTableFromOLAPTable(database, (Table) relation);
} else if (relation instanceof View) {
throw new UnsupportedOperationException("Views not implemented
yet");
} else if (relation instanceof InlineTable) {
@@ -257,7 +246,34 @@
} else if (relation instanceof Join) {
throw new UnsupportedOperationException("Join not implemented
yet");
} else {
- throw new IllegalStateException("Can't produce SQLTable for
unknown Relation type " + relation.getClass().getName());
+ throw new IllegalStateException("Can't produce SQLTable for
unknown Relation type " +
+ relation.getClass().getName());
+ }
+ }
+
+ /**
+ * Search the database and retrieve the matching SQLTable(Relational)
object
+ * thats logically equivalent to the given Table(OLAP representation)
+ *
+ * @param table Table object representing a table in a relational
database
+ * @return a SQLTable in SQLDatabase representing the given table
+ * @throws ArchitectException
+ */
+ public static SQLTable getSQLTableFromOLAPTable(SQLDatabase database,
Table table) throws ArchitectException {
+ String qualifier = table.getSchema();
+ String name = table.getName();
+ if (qualifier == null || qualifier.length() == 0) {
+ return (SQLTable) database.getChildByName(name);
+ } else if (qualifier.contains(".")) {
+ String cat = qualifier.substring(0, qualifier.indexOf('.'));
+ String schema = qualifier.substring(qualifier.indexOf('.') +
1);
+ return database.getTableByName(cat, schema, name);
+ } else if (ArchitectUtils.isCompatibleWithHierarchy(database,
qualifier, null, name)) {
+ return database.getTableByName(qualifier, null, name);
+ } else if (ArchitectUtils.isCompatibleWithHierarchy(database,
null, qualifier, name)) {
+ return database.getTableByName(null, qualifier, name);
+ } else {
+ return null;
}
}
@@ -270,8 +286,8 @@
* @return The list of all accessible tables. If the OLAP session
doesn't
* have a database chosen, an empty list is returned.
* @throws ArchitectException
- * If there is a problem populating the list of tables
(for example,
- * the database might not be reachable).
+ * If there is a problem populating the list of tables (for
+ * example, the database might not be reachable).
*/
public static List<SQLTable> getAvailableTables(OLAPObject obj) throws
ArchitectException {
OLAPSession osession = OLAPUtil.getSession(obj);
@@ -284,7 +300,7 @@
}
return tables;
}
-
+
/**
* Finds and returns the Cube that the given CubeUsage references.
*
@@ -301,8 +317,8 @@
throw new IllegalArgumentException("Can't find OLAPSession
ancestor: " + cu);
}
return olapSession.findCube(cu.getCubeName());
- }
-
+ }
+
/**
* Finds and returns the base Dimension that the given CubeDimension
* references. It is safe to call this method with a Dimension as
parameter,
@@ -319,7 +335,7 @@
if (olapSession == null) {
throw new IllegalArgumentException("Can't find OLAPSession
ancestor: " + cubeDim);
}
-
+
if (cubeDim instanceof Dimension) {
return (Dimension) cubeDim;
} else if (cubeDim instanceof DimensionUsage) {
@@ -331,7 +347,7 @@
return olapSession.findPublicDimension(vCubeDim.getName());
} else {
CubeDimension cd =
olapSession.findCubeDimension(vCubeDim.getCubeName(), vCubeDim.getName());
-
+
if (cd == null) {
return null;
} else if (cd instanceof Dimension) {
@@ -348,7 +364,7 @@
throw new UnsupportedOperationException("CubeDimension of
type " + cubeDim.getClass() + " not recognized.");
}
}
-
+
/**
* Checks if the name is unique for an OLAPObject, relies on
* [EMAIL PROTECTED] OLAPObject#getName()} for name comparisons, case
insensitive.
@@ -367,7 +383,7 @@
if (olapSession == null) {
throw new IllegalArgumentException("Can't find OLAPSession
ancestor: " + parent);
}
-
+
if (type == Cube.class) {
return olapSession.findCube(name) == null;
} else if (type == Dimension.class && parent instanceof Schema) {
Modified: trunk/src/ca/sqlpower/architect/swingui/olap/CubePane.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/CubePane.java (original)
+++ trunk/src/ca/sqlpower/architect/swingui/olap/CubePane.java Wed Aug 27
13:51:06 2008
@@ -96,7 +96,9 @@
panel = new MeasureEditPanel((Measure) coord.getItem());
} else if (coord.getItem() instanceof DimensionUsage) {
UsageComponent usageComp = (UsageComponent)
getPlayPen().findPPComponent(coord.getItem());
- panel = new DimensionEditPanel((Dimension)
usageComp.getPane1().getModel());
+ Dimension dimension = (Dimension)
usageComp.getPane1().getModel();
+ DimensionUsage dimensionUsage = (DimensionUsage)
usageComp.getModel();
+ panel = new DimensionUsageEditPanel(dimensionUsage,
dimension);
} else {
throw new IllegalArgumentException("Edit dialog for type "
+ coord.getItem().getClass() + " cannot be created!");
}
Added:
trunk/src/ca/sqlpower/architect/swingui/olap/DimensionUsageEditPanel.java
==============================================================================
--- (empty file)
+++
trunk/src/ca/sqlpower/architect/swingui/olap/DimensionUsageEditPanel.java
Wed Aug 27 13:51:06 2008
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2008, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * Power*Architect is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Power*Architect is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package ca.sqlpower.architect.swingui.olap;
+
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import ca.sqlpower.architect.ArchitectException;
+import ca.sqlpower.architect.SQLColumn;
+import ca.sqlpower.architect.SQLTable;
+import ca.sqlpower.architect.olap.OLAPUtil;
+import ca.sqlpower.architect.olap.MondrianModel.Cube;
+import ca.sqlpower.architect.olap.MondrianModel.Dimension;
+import ca.sqlpower.architect.olap.MondrianModel.DimensionUsage;
+import ca.sqlpower.architect.olap.MondrianModel.Table;
+import ca.sqlpower.swingui.DataEntryPanel;
+
+import com.jgoodies.forms.builder.DefaultFormBuilder;
+import com.jgoodies.forms.layout.FormLayout;
+
+public class DimensionUsageEditPanel implements DataEntryPanel{
+
+ private final DimensionUsage dimensionUsage;
+
+ private final JPanel panel;
+
+ private JTextField captionField;
+
+ private JComboBox foreignKeyChooser;
+
+ private final Dimension dimension;
+
+ /**
+ * Creates a new property editor for the given dimension usage.
+ *
+ * @param dimensionUsage
+ * usage The data model of the dimension usage to edit
+ * @param dimension
+ * The dimension this dimension usage is referring to
+ *
+ * @throws ArchitectException
+ * if digging up the source table results in a database
error
+ */
+ public DimensionUsageEditPanel(DimensionUsage dimensionUsage,
Dimension dimension) throws ArchitectException {
+ this.dimensionUsage = dimensionUsage;
+ this.dimension = dimension;
+
+ FormLayout layout = new FormLayout("left:max(40dlu;pref), 3dlu,
80dlu:grow", "");
+ DefaultFormBuilder builder = new DefaultFormBuilder(layout);
+ builder.setDefaultDialogBorder();
+ builder.append("Caption", captionField = new
JTextField(dimensionUsage.getCaption()));
+ builder.append("Foreign Key", foreignKeyChooser = new JComboBox());
+
+ Cube cube = (Cube) dimensionUsage.getParent();
+ SQLTable factTable =
OLAPUtil.getSQLTableFromOLAPTable(OLAPUtil.getSession(cube).getDatabase(),
(Table) (cube.getFact()));
+ for (SQLColumn col : factTable.getColumns()) {
+ foreignKeyChooser.addItem(col);
+ if (col.getName().equals(dimensionUsage.getForeignKey())) {
+ foreignKeyChooser.setSelectedItem(col);
+ }
+ }
+ panel = builder.getPanel();
+ }
+
+ public boolean applyChanges() {
+ dimensionUsage.startCompoundEdit("Modify Dimension Usage
Properties");
+ if (!(captionField.getText().equals(""))) {
+ dimensionUsage.setCaption(captionField.getText());
+ } else {
+ dimensionUsage.setCaption(null);
+ }
+ SQLColumn selectedCol = (SQLColumn)
foreignKeyChooser.getSelectedItem();
+ String pk = selectedCol.getName();
+ dimensionUsage.setForeignKey(pk);
+ dimension.setForeignKey(pk);
+ dimensionUsage.endCompoundEdit();
+ return true;
+ }
+
+ public void discardChanges() {
+ // nothing to do
+ }
+
+ public JComponent getPanel() {
+ return panel;
+ }
+
+ public boolean hasUnsavedChanges() {
+ return true;
+ }
+}
Modified:
trunk/src/ca/sqlpower/architect/swingui/olap/HierarchyEditPanel.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/olap/HierarchyEditPanel.java
(original)
+++ trunk/src/ca/sqlpower/architect/swingui/olap/HierarchyEditPanel.java
Wed Aug 27 13:51:06 2008
@@ -19,7 +19,6 @@
package ca.sqlpower.architect.swingui.olap;
-import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
@@ -30,7 +29,6 @@
import javax.swing.JTextField;
import ca.sqlpower.architect.ArchitectException;
-import ca.sqlpower.architect.SQLColumn;
import ca.sqlpower.architect.SQLTable;
import ca.sqlpower.architect.olap.OLAPUtil;
import ca.sqlpower.architect.olap.MondrianModel.Hierarchy;
@@ -53,7 +51,6 @@
private final JComboBox tableChooser;
private final JCheckBox hasAll;
private final JTextField allLevelName;
- private final JComboBox primaryKeyName;
/**
* Validation handler for errors in the dialog
@@ -83,22 +80,6 @@
builder.append("Table", tableChooser = new JComboBox(new
Vector<SQLTable>(tables)));
builder.append("All Level Name", allLevelName = new
JTextField(hierarchy.getAllLevelName() != null ?
hierarchy.getAllLevelName() : "(All)"));
tableChooser.setSelectedItem(OLAPUtil.tableForHierarchy(hierarchy)); // XXX
this isn't quite right.. it would set the default as the local value
- SQLTable selectedTable = (SQLTable) tableChooser.getSelectedItem();
- List<SQLColumn> pk = new ArrayList<SQLColumn>();
- if (selectedTable != null) {
- for (SQLColumn col : selectedTable.getColumns()) {
- if (col.isPrimaryKey()) {
- pk.add(col);
- }
- }
- if (pk.isEmpty()) {
- throw new IllegalStateException("Primary key in a
hierarchy should always be " +
- "specified from the selected table, but selected table
contains no primary key");
- }
- } else {
- throw new NullPointerException("Selected source table must not
be null");
- }
- builder.append("Primary Key", primaryKeyName = new JComboBox(new
Vector<SQLColumn>(pk)));
handler = new FormValidationHandler(status);
Validator validator = new
OLAPObjectNameValidator(hierarchy.getParent(), hierarchy, true);
@@ -127,8 +108,6 @@
hierarchy.setRelation(table);
}
hierarchy.setAllLevelName(allLevelName.getText());
- SQLColumn column = (SQLColumn) primaryKeyName.getSelectedItem();
- hierarchy.setPrimaryKey(column.getName());
hierarchy.endCompoundEdit();
return true;
}
Modified:
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateDimensionUsageAction.java
==============================================================================
---
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateDimensionUsageAction.java
(original)
+++
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateDimensionUsageAction.java
Wed Aug 27 13:51:06 2008
@@ -19,17 +19,35 @@
package ca.sqlpower.architect.swingui.olap.action;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import javax.swing.JDialog;
import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
import org.apache.log4j.Logger;
+import ca.sqlpower.architect.ArchitectException;
+import ca.sqlpower.architect.ArchitectRuntimeException;
+import ca.sqlpower.architect.SQLColumn;
+import ca.sqlpower.architect.SQLRelationship;
+import ca.sqlpower.architect.SQLTable;
+import ca.sqlpower.architect.SQLRelationship.ColumnMapping;
import ca.sqlpower.architect.olap.OLAPUtil;
+import ca.sqlpower.architect.olap.MondrianModel.Cube;
+import ca.sqlpower.architect.olap.MondrianModel.Dimension;
import ca.sqlpower.architect.olap.MondrianModel.DimensionUsage;
+import ca.sqlpower.architect.olap.MondrianModel.Hierarchy;
+import ca.sqlpower.architect.olap.MondrianModel.Table;
import ca.sqlpower.architect.swingui.ArchitectSwingSession;
import ca.sqlpower.architect.swingui.PlayPen;
import ca.sqlpower.architect.swingui.olap.CubePane;
import ca.sqlpower.architect.swingui.olap.DimensionPane;
+import ca.sqlpower.architect.swingui.olap.DimensionUsageEditPanel;
import ca.sqlpower.architect.swingui.olap.UsageComponent;
+import ca.sqlpower.swingui.DataEntryPanel;
+import ca.sqlpower.swingui.DataEntryPanelBuilder;
/**
* Creates a dimension usage after the user clicks a DimensionPane and a
@@ -46,15 +64,64 @@
@Override
protected void createUsage(DimensionPane dp, CubePane cp) {
- if (OLAPUtil.isNameUnique(cp.getModel(), DimensionUsage.class,
dp.getModel().getName())) {
- DimensionUsage du = new DimensionUsage();
- du.setName(dp.getModel().getName());
- du.setSource(dp.getModel().getName());
- cp.getModel().addChild(du);
+ final Dimension dimension = dp.getModel();
+ final Cube cube = cp.getModel();
+ if (OLAPUtil.isNameUnique(cp.getModel(), DimensionUsage.class,
dimension.getName())) {
+ final DimensionUsage du = new DimensionUsage();
+ du.setName(dimension.getName());
+ du.setSource(dimension.getName());
+ cube.addChild(du);
UsageComponent uc = new
UsageComponent(playpen.getContentPane(), du, dp, cp);
playpen.getContentPane().add(uc,
playpen.getContentPane().getComponentCount());
+
+ try {
+ SQLTable factTable =
OLAPUtil.getSQLTableFromOLAPTable(OLAPUtil.getSession(cube).getDatabase(),
(Table) (cube.getFact()));
+ SQLColumn defaultFK;
+ // If there is a relationship between the fact table and
the dimension table,
+ // by default, the usage takes the mapped foreign key.
+ if (!factTable.getExportedKeys().isEmpty()) {
+ SQLRelationship relationship =
factTable.getExportedKeys().get(0);
+ List<ColumnMapping> mappings =
relationship.getMappings();
+ defaultFK = mappings.get(0).getFkColumn();
+ du.setForeignKey(defaultFK.toString());
+ dimension.setForeignKey(defaultFK.toString());
+ // Further set all the hierarchy primary key to
default value.
+ for (Hierarchy hierarchy : dimension.getHierarchies())
{
+ hierarchy.setPrimaryKey(defaultFK.toString());
+ }
+ } else {
+
+ final DataEntryPanel mep = new
DimensionUsageEditPanel(du, dimension);
+ Callable<Boolean> okCall = new Callable<Boolean>() {
+ public Boolean call() throws Exception {
+ // Further set all the hierarchy primary key
to default value on the first run.
+ for (Hierarchy hierarchy :
dimension.getHierarchies()) {
+
hierarchy.setPrimaryKey(dimension.getForeignKey());
+ }
+ return mep.applyChanges();
+ }
+ };
+ Callable<Boolean> cancelCall = new Callable<Boolean>()
{
+ public Boolean call() throws Exception {
+ du.getParent().removeChild(du);
+ return true;
+ }
+ };
+ JDialog d =
DataEntryPanelBuilder.createDataEntryPanelDialog(
+ mep,
+ SwingUtilities.getWindowAncestor(playpen),
+ "Dimension Usage Properties",
+ "OK",
+ okCall,
+ cancelCall);
+ d.setLocationRelativeTo(playpen);
+ d.setVisible(true);
+ }
+ } catch (ArchitectException e) {
+ throw new ArchitectRuntimeException(e);
+ }
} else {
- String errorMsg = "Cube Dimension \"" +
dp.getModel().getName() + "\" already exists in \"" +
+ String errorMsg = "Cube Dimension \"" + dimension.getName()
+ "\" already exists in \"" +
cp.getModel().getName() + "\".\nDimension Usage was
not created.";
JOptionPane.showMessageDialog(playpen, errorMsg, "Duplicate
Cube Dimension", JOptionPane.INFORMATION_MESSAGE);
}
Modified:
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateHierarchyAction.java
==============================================================================
---
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateHierarchyAction.java
(original)
+++
trunk/src/ca/sqlpower/architect/swingui/olap/action/CreateHierarchyAction.java
Wed Aug 27 13:51:06 2008
@@ -22,6 +22,7 @@
import ca.sqlpower.architect.ArchitectException;
import ca.sqlpower.architect.ArchitectRuntimeException;
import ca.sqlpower.architect.olap.OLAPUtil;
+import ca.sqlpower.architect.olap.MondrianModel.Dimension;
import ca.sqlpower.architect.olap.MondrianModel.Hierarchy;
import ca.sqlpower.architect.swingui.ArchitectSwingSession;
import ca.sqlpower.architect.swingui.PlayPen;
@@ -49,6 +50,16 @@
h.setName("New Hierarchy " + count);
pane.getModel().addHierarchy(h);
+ /*
+ * If parent dimension is a private dimension, then first default
the
+ * parimaryKey value to the foreignKey value of the parent
dimension. A
+ * user is still able to modify this property.
+ */
+ Dimension dimension = (Dimension) h.getParent();
+ if (dimension.getForeignKey() != null) {
+ h.setPrimaryKey(dimension.getForeignKey());
+ }
+
return h;
}