提交 8b4f6243 编写于 作者: S serge-rider

ERD: association auto-create model

Former-commit-id: 67be9d55
上级 38e8566d
......@@ -83,7 +83,7 @@ public class EntityAddCommand extends Command
null);
// This actually only loads unresolved relations.
// This happens only with entities added on diagram during editing
entity.addModelRelations(monitor, diagramPart.getDiagram().getEntityMap(), false, false);
entity.addModelRelations(monitor, diagramPart.getDiagram(), false, false);
}
}
}
......
......@@ -23,7 +23,6 @@ import org.jkiss.dbeaver.ext.erd.ERDConstants;
import org.jkiss.dbeaver.model.DBPNamedObject;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress;
import org.jkiss.dbeaver.model.struct.*;
import org.jkiss.dbeaver.model.struct.rdb.DBSTable;
import org.jkiss.dbeaver.ui.UIUtils;
......@@ -41,12 +40,10 @@ public class DiagramObjectCollector {
private final EntityDiagram diagram;
private final List<ERDEntity> erdEntities = new ArrayList<>();
private final Map<DBSEntity, ERDEntity> tableMap = new HashMap<>();
public DiagramObjectCollector(EntityDiagram diagram)
{
this.diagram = diagram;
this.tableMap.putAll(diagram.getEntityMap());
}
public static Collection<DBSEntity> collectTables(
......@@ -134,7 +131,7 @@ public class DiagramObjectCollector {
// Add new relations
for (ERDEntity erdEntity : erdEntities) {
erdEntity.addModelRelations(monitor, tableMap, true, false);
erdEntity.addModelRelations(monitor, diagram, true, false);
}
}
......@@ -147,7 +144,6 @@ public class DiagramObjectCollector {
ERDEntity erdEntity = ERDUtils.makeEntityFromObject(monitor, diagram, table, null);
if (erdEntity != null) {
erdEntities.add(erdEntity);
tableMap.put(table, erdEntity);
}
}
......
......@@ -89,7 +89,7 @@ public class ERDAssociation extends ERDObject<DBSEntityAssociation>
this.sourceEntity.addAssociation(this, reflect);
}
private void resolveAttributes(DBSEntityReferrer association, ERDEntity sourceEntity, ERDEntity targetEntity) {
protected void resolveAttributes(DBSEntityReferrer association, ERDEntity sourceEntity, ERDEntity targetEntity) {
try {
List<? extends DBSEntityAttributeRef> attrRefs = association.getAttributeReferences(new VoidProgressMonitor());
......
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2018 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.ext.erd.model;
import org.jkiss.dbeaver.model.struct.DBSEntity;
import java.util.Map;
/**
* ERD object container (diagram)
*/
public interface ERDContainer {
ERDDecorator getDecorator();
Map<DBSEntity, ERDEntity> getEntityMap();
}
......@@ -16,11 +16,12 @@
*/
package org.jkiss.dbeaver.ext.erd.model;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartFactory;
import org.eclipse.gef.palette.PaletteRoot;
import org.jkiss.dbeaver.ext.erd.part.EntityPart;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.DBSEntityAssociation;
/**
* ERD object adapter
......@@ -31,10 +32,13 @@ public interface ERDDecorator {
boolean allowEntityDuplicates();
@NotNull
EditPartFactory createPartFactory();
void fillPalette(PaletteRoot paletteRoot, boolean readOnly);
void fillPalette(@NotNull PaletteRoot paletteRoot, boolean readOnly);
void fillEntityFromObject(DBRProgressMonitor monitor, EntityDiagram diagram, ERDEntity erdEntity);
void fillEntityFromObject(@NotNull DBRProgressMonitor monitor, @NotNull EntityDiagram diagram, @NotNull ERDEntity erdEntity);
@Nullable
ERDAssociation createAutoAssociation(@NotNull DBSEntityAssociation association, @NotNull ERDEntity sourceEntity, @NotNull ERDEntity targetEntity, boolean reflect);
}
......@@ -192,4 +192,10 @@ public class ERDDecoratorDefault implements ERDDecorator {
}
}
@Override
public ERDAssociation createAutoAssociation(DBSEntityAssociation association, ERDEntity sourceEntity, ERDEntity targetEntity, boolean reflect) {
// Allow all auto-associations
return new ERDAssociation(association, sourceEntity, targetEntity, reflect);
}
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2018 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created on Jul 13, 2004
*/
package org.jkiss.dbeaver.ext.erd.model;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.*;
import org.jkiss.utils.CommonUtils;
import java.util.*;
/**
* Model object representing a relational database Table
* Also includes the bounds of the table so that the diagram can be
* restored following a save, although ideally this should be
* in a separate diagram specific model hierarchy
*/
public class ERDEntity extends ERDObject<DBSEntity> {
static final Log log = Log.getLog(ERDEntity.class);
private DBPDataSource dataSource;
private String alias;
private List<ERDEntityAttribute> attributes;
private List<ERDAssociation> references;
private List<ERDAssociation> associations;
private List<DBSEntityAssociation> unresolvedKeys;
private boolean primary = false;
/**
* Special constructore for creating lazy entities.
* This entity will be initialized at the moment of creation within diagram.
*/
public ERDEntity(DBPDataSource dataSource) {
super(null);
this.dataSource = dataSource;
}
public ERDEntity(DBSEntity entity) {
super(entity);
}
public DBPDataSource getDataSource() {
return dataSource;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public void addAttribute(ERDEntityAttribute attribute, boolean reflect) {
if (attributes == null) {
attributes = new ArrayList<>();
}
if (attributes.contains(attribute)) {
throw new IllegalArgumentException("Attribute already present");
}
attributes.add(attribute);
if (reflect) {
firePropertyChange(CHILD, null, attribute);
}
}
public void removeAttribute(ERDEntityAttribute attribute, boolean reflect) {
attributes.remove(attribute);
if (reflect) {
firePropertyChange(CHILD, attribute, null);
}
}
public void switchAttribute(ERDEntityAttribute attribute, int index, boolean reflect) {
attributes.remove(attribute);
attributes.add(index, attribute);
if (reflect) {
firePropertyChange(REORDER, this, attribute);
}
}
/**
* Adds relationship where the current object is the foreign key table in a relationship
*
* @param rel the primary key relationship
*/
public void addAssociation(ERDAssociation rel, boolean reflect) {
if (associations == null) {
associations = new ArrayList<>();
}
associations.add(rel);
if (reflect) {
firePropertyChange(OUTPUT, null, rel);
}
}
/**
* Adds relationship where the current object is the primary key table in a relationship
*
* @param table the foreign key relationship
*/
public void addReferenceAssociation(ERDAssociation table, boolean reflect) {
if (references == null) {
references = new ArrayList<>();
}
references.add(table);
if (reflect) {
firePropertyChange(INPUT, null, table);
}
}
/**
* Removes relationship where the current object is the foreign key table in a relationship
*
* @param table the primary key relationship
*/
public void removeAssociation(ERDAssociation table, boolean reflect) {
associations.remove(table);
if (reflect) {
firePropertyChange(OUTPUT, table, null);
}
}
/**
* Removes relationship where the current object is the primary key table in a relationship
*
* @param table the foreign key relationship
*/
public void removeReferenceAssociation(ERDAssociation table, boolean reflect) {
references.remove(table);
if (reflect) {
firePropertyChange(INPUT, table, null);
}
}
@NotNull
public List<ERDEntityAttribute> getAttributes() {
return CommonUtils.safeList(attributes);
}
@NotNull
public List<ERDEntityAttribute> getCheckedAttributes() {
List<ERDEntityAttribute> result = new ArrayList<>();
if (attributes != null) {
for (ERDEntityAttribute attr : attributes) {
if (attr.isChecked()) {
result.add(attr);
}
}
}
return result;
}
/**
* @return Returns the associations.
*/
public List<ERDAssociation> getAssociations() {
return CommonUtils.safeList(associations);
}
/**
* @return Returns the references.
*/
public List<ERDAssociation> getReferences() {
return CommonUtils.safeList(references);
}
public boolean isPrimary() {
return primary;
}
public void setPrimary(boolean primary) {
this.primary = primary;
}
public boolean hasSelfLinks() {
if (associations != null) {
for (ERDAssociation association : associations) {
if (association.getTargetEntity() == this) {
return true;
}
}
}
return false;
}
/**
* Resolve and create entity associations.
* Also caches all unresolved associations (associations with entities which are not present in diagram yet)
* @param tableMap all diagram entities map
* @param create if true then creates all found model association. Otherwise only saves unresolved ones.
* @param reflect reflect UI
*/
public void addModelRelations(DBRProgressMonitor monitor, Map<DBSEntity, ERDEntity> tableMap, boolean create, boolean reflect) {
try {
Set<DBSEntityAttribute> fkAttrs = new HashSet<>();
// Make associations
Collection<? extends DBSEntityAssociation> fks = getObject().getAssociations(monitor);
if (fks != null) {
for (DBSEntityAssociation fk : fks) {
if (fk instanceof DBSEntityReferrer) {
fkAttrs.addAll(DBUtils.getEntityAttributes(monitor, (DBSEntityReferrer) fk));
}
ERDEntity entity2 = tableMap.get(fk.getAssociatedEntity());
if (entity2 == null) {
//log.debug("Table '" + fk.getReferencedKey().getTable().getFullyQualifiedName() + "' not found in ERD");
if (unresolvedKeys == null) {
unresolvedKeys = new ArrayList<>();
}
unresolvedKeys.add(fk);
} else {
if (create) {
new ERDAssociation(fk, this, entity2, reflect);
}
}
}
}
// Mark attribute's fk flag
for (ERDEntityAttribute attribute : this.getAttributes()) {
if (fkAttrs.contains(attribute.getObject())) {
attribute.setInForeignKey(true);
}
}
} catch (DBException e) {
log.warn("Can't load table '" + getObject().getName() + "' foreign keys", e);
}
}
public void resolveRelations(Map<DBSEntity, ERDEntity> tableMap, boolean reflect) {
if (CommonUtils.isEmpty(unresolvedKeys)) {
return;
}
for (Iterator<DBSEntityAssociation> iter = unresolvedKeys.iterator(); iter.hasNext(); ) {
final DBSEntityAssociation fk = iter.next();
if (fk.getReferencedConstraint() != null) {
ERDEntity refEntity = tableMap.get(fk.getReferencedConstraint().getParentObject());
if (refEntity != null) {
new ERDAssociation(fk, this, refEntity, reflect);
iter.remove();
}
}
}
}
@NotNull
@Override
public String getName() {
return getObject().getName();
}
@Override
public String toString() {
return object.getName();
}
@Override
public int hashCode() {
return object == null ? 0 : object.hashCode();
}
@Override
public boolean equals(Object o) {
return o != null && o instanceof ERDEntity &&
CommonUtils.equalObjects(object, ((ERDEntity) o).object);
}
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2018 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Created on Jul 13, 2004
*/
package org.jkiss.dbeaver.ext.erd.model;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.*;
import org.jkiss.utils.CommonUtils;
import java.util.*;
/**
* Model object representing a relational database Table
* Also includes the bounds of the table so that the diagram can be
* restored following a save, although ideally this should be
* in a separate diagram specific model hierarchy
*/
public class ERDEntity extends ERDObject<DBSEntity> {
static final Log log = Log.getLog(ERDEntity.class);
private DBPDataSource dataSource;
private String alias;
private List<ERDEntityAttribute> attributes;
private List<ERDAssociation> references;
private List<ERDAssociation> associations;
private List<DBSEntityAssociation> unresolvedKeys;
private boolean primary = false;
/**
* Special constructore for creating lazy entities.
* This entity will be initialized at the moment of creation within diagram.
*/
public ERDEntity(DBPDataSource dataSource) {
super(null);
this.dataSource = dataSource;
}
public ERDEntity(DBSEntity entity) {
super(entity);
}
public DBPDataSource getDataSource() {
return dataSource;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public void addAttribute(ERDEntityAttribute attribute, boolean reflect) {
if (attributes == null) {
attributes = new ArrayList<>();
}
if (attributes.contains(attribute)) {
throw new IllegalArgumentException("Attribute already present");
}
attributes.add(attribute);
if (reflect) {
firePropertyChange(CHILD, null, attribute);
}
}
public void removeAttribute(ERDEntityAttribute attribute, boolean reflect) {
attributes.remove(attribute);
if (reflect) {
firePropertyChange(CHILD, attribute, null);
}
}
public void switchAttribute(ERDEntityAttribute attribute, int index, boolean reflect) {
attributes.remove(attribute);
attributes.add(index, attribute);
if (reflect) {
firePropertyChange(REORDER, this, attribute);
}
}
/**
* Adds relationship where the current object is the foreign key table in a relationship
*
* @param rel the primary key relationship
*/
public void addAssociation(ERDAssociation rel, boolean reflect) {
if (associations == null) {
associations = new ArrayList<>();
}
associations.add(rel);
if (reflect) {
firePropertyChange(OUTPUT, null, rel);
}
}
/**
* Adds relationship where the current object is the primary key table in a relationship
*
* @param table the foreign key relationship
*/
public void addReferenceAssociation(ERDAssociation table, boolean reflect) {
if (references == null) {
references = new ArrayList<>();
}
references.add(table);
if (reflect) {
firePropertyChange(INPUT, null, table);
}
}
/**
* Removes relationship where the current object is the foreign key table in a relationship
*
* @param table the primary key relationship
*/
public void removeAssociation(ERDAssociation table, boolean reflect) {
associations.remove(table);
if (reflect) {
firePropertyChange(OUTPUT, table, null);
}
}
/**
* Removes relationship where the current object is the primary key table in a relationship
*
* @param table the foreign key relationship
*/
public void removeReferenceAssociation(ERDAssociation table, boolean reflect) {
references.remove(table);
if (reflect) {
firePropertyChange(INPUT, table, null);
}
}
@NotNull
public List<ERDEntityAttribute> getAttributes() {
return CommonUtils.safeList(attributes);
}
@NotNull
public List<ERDEntityAttribute> getCheckedAttributes() {
List<ERDEntityAttribute> result = new ArrayList<>();
if (attributes != null) {
for (ERDEntityAttribute attr : attributes) {
if (attr.isChecked()) {
result.add(attr);
}
}
}
return result;
}
/**
* @return Returns the associations.
*/
public List<ERDAssociation> getAssociations() {
return CommonUtils.safeList(associations);
}
/**
* @return Returns the references.
*/
public List<ERDAssociation> getReferences() {
return CommonUtils.safeList(references);
}
public boolean isPrimary() {
return primary;
}
public void setPrimary(boolean primary) {
this.primary = primary;
}
public boolean hasSelfLinks() {
if (associations != null) {
for (ERDAssociation association : associations) {
if (association.getTargetEntity() == this) {
return true;
}
}
}
return false;
}
/**
* Resolve and create entity associations.
* Also caches all unresolved associations (associations with entities which are not present in diagram yet)
* @param diagram all diagram entities map
* @param create if true then creates all found model association. Otherwise only saves unresolved ones.
* @param reflect reflect UI
*/
public void addModelRelations(DBRProgressMonitor monitor, ERDContainer diagram, boolean create, boolean reflect) {
try {
Set<DBSEntityAttribute> fkAttrs = new HashSet<>();
// Make associations
Collection<? extends DBSEntityAssociation> fks = getObject().getAssociations(monitor);
if (fks != null) {
for (DBSEntityAssociation fk : fks) {
if (fk instanceof DBSEntityReferrer) {
fkAttrs.addAll(DBUtils.getEntityAttributes(monitor, (DBSEntityReferrer) fk));
}
ERDEntity entity2 = diagram.getEntityMap().get(fk.getAssociatedEntity());
if (entity2 == null) {
//log.debug("Table '" + fk.getReferencedKey().getTable().getFullyQualifiedName() + "' not found in ERD");
if (unresolvedKeys == null) {
unresolvedKeys = new ArrayList<>();
}
unresolvedKeys.add(fk);
} else {
if (create) {
diagram.getDecorator().createAutoAssociation(fk, this, entity2, reflect);
}
}
}
}
// Mark attribute's fk flag
for (ERDEntityAttribute attribute : this.getAttributes()) {
if (fkAttrs.contains(attribute.getObject())) {
attribute.setInForeignKey(true);
}
}
} catch (DBException e) {
log.warn("Can't load table '" + getObject().getName() + "' foreign keys", e);
}
}
public void resolveRelations(ERDContainer diagram, boolean reflect) {
if (CommonUtils.isEmpty(unresolvedKeys)) {
return;
}
for (Iterator<DBSEntityAssociation> iter = unresolvedKeys.iterator(); iter.hasNext(); ) {
final DBSEntityAssociation fk = iter.next();
if (fk.getReferencedConstraint() != null) {
ERDEntity refEntity = diagram.getEntityMap().get(fk.getReferencedConstraint().getParentObject());
if (refEntity != null) {
ERDAssociation erdAssociation = diagram.getDecorator().createAutoAssociation(fk, this, refEntity, reflect);
if (erdAssociation != null) {
iter.remove();
}
}
}
}
}
@NotNull
@Override
public String getName() {
return getObject().getName();
}
@Override
public String toString() {
return object.getName();
}
@Override
public int hashCode() {
return object == null ? 0 : object.hashCode();
}
@Override
public boolean equals(Object o) {
return o != null && o instanceof ERDEntity &&
CommonUtils.equalObjects(object, ((ERDEntity) o).object);
}
public boolean hasAssociationsWith(ERDEntity entity) {
if (associations != null) {
for (ERDAssociation assoc : associations) {
if (assoc.getTargetEntity() == entity) {
return true;
}
}
}
return false;
}
}
......@@ -41,7 +41,7 @@ import java.util.*;
*
* @author Serge Rider
*/
public class EntityDiagram extends ERDObject<DBSObject> {
public class EntityDiagram extends ERDObject<DBSObject> implements ERDContainer {
public static class NodeVisualInfo {
public Rectangle initBounds;
public Color bgColor;
......@@ -150,7 +150,7 @@ public class EntityDiagram extends ERDObject<DBSObject> {
private void resolveRelations(boolean reflect) {
// Resolve incomplete relations
for (ERDEntity erdEntity : getEntities()) {
erdEntity.resolveRelations(entityMap, reflect);
erdEntity.resolveRelations(this, reflect);
}
}
......@@ -278,7 +278,7 @@ public class EntityDiagram extends ERDObject<DBSObject> {
monitor.subTask("Load " + table.getName());
final ERDEntity erdEntity = entityMap.get(table);
if (erdEntity != null) {
erdEntity.addModelRelations(monitor, entityMap, true, false);
erdEntity.addModelRelations(monitor, this, true, false);
}
monitor.worked(1);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册