further cleaned up things around DbMapping and Relation - more to come

This commit is contained in:
hns 2001-08-08 10:14:24 +00:00
parent e8f3e04637
commit 18e3d82166
4 changed files with 171 additions and 79 deletions

View file

@ -37,11 +37,14 @@ public class DbMapping implements Updatable {
ParentInfo[] parent; // list of properties to try for parent ParentInfo[] parent; // list of properties to try for parent
DbMapping subnodes; // DbMapping subnodes;
DbMapping properties; // DbMapping properties;
Relation subnodesRel; Relation subnodesRel;
Relation propertiesRel; Relation propertiesRel;
// if this defines a subnode mapping with groupby layer, we need a DbMapping for those groupby nodes
DbMapping groupbyMapping;
// Map of property names to Relations objects // Map of property names to Relations objects
Hashtable prop2db; Hashtable prop2db;
// Map of db columns to Relations objects // Map of db columns to Relations objects
@ -88,8 +91,8 @@ public class DbMapping implements Updatable {
db2prop = new Hashtable (); db2prop = new Hashtable ();
parent = null; parent = null;
subnodes = null; // subnodes = null;
properties = null; // properties = null;
idField = "id"; idField = "id";
} }
@ -105,8 +108,8 @@ public class DbMapping implements Updatable {
db2prop = new Hashtable (); db2prop = new Hashtable ();
parent = null; parent = null;
subnodes = null; // subnodes = null;
properties = null; // properties = null;
idField = "id"; idField = "id";
this.props = props; this.props = props;
@ -191,9 +194,16 @@ public class DbMapping implements Updatable {
try { try {
if (!propName.startsWith ("_") && propName.indexOf (".") < 0) { if (!propName.startsWith ("_") && propName.indexOf (".") < 0) {
String dbField = props.getProperty (propName); String dbField = props.getProperty (propName);
Relation rel = new Relation (dbField, propName, this, props); // check if a relation for this propery already exists. If so, reuse it
Relation rel = propertyToRelation (propName);
if (rel == null)
rel = new Relation (dbField, propName, this, props);
else
rel.update (dbField, props);
p2d.put (propName, rel); p2d.put (propName, rel);
if (rel.localField != null) if (rel.localField != null &&
(rel.direction == Relation.PRIMITIVE ||
rel.direction == Relation.FORWARD))
d2p.put (rel.localField, rel); d2p.put (rel.localField, rel);
// app.logEvent ("Mapping "+propName+" -> "+dbField); // app.logEvent ("Mapping "+propName+" -> "+dbField);
} }
@ -208,14 +218,18 @@ public class DbMapping implements Updatable {
String subnodeMapping = props.getProperty ("_subnodes"); String subnodeMapping = props.getProperty ("_subnodes");
if (subnodeMapping != null) { if (subnodeMapping != null) {
try { try {
subnodesRel = new Relation (subnodeMapping, "_subnodes", this, props); // check if subnode relation already exists. If so, reuse it
if (subnodesRel.isReference ()) if (subnodesRel == null)
subnodes = subnodesRel.other; subnodesRel = new Relation (subnodeMapping, "_subnodes", this, props);
else else
subnodes = (DbMapping) app.getDbMapping (subnodeMapping); subnodesRel.update (subnodeMapping, props);
// if (subnodesRel.isReference ())
// subnodes = subnodesRel.other;
// else
// subnodes = (DbMapping) app.getDbMapping (subnodeMapping);
} catch (Exception x) { } catch (Exception x) {
app.logEvent ("Error in type.properties: "+x.getMessage ()); app.logEvent ("Error reading _subnodes relation for "+typename+": "+x.getMessage ());
subnodesRel = null; // subnodesRel = null;
} }
} else } else
subnodesRel = null; subnodesRel = null;
@ -223,22 +237,30 @@ public class DbMapping implements Updatable {
String propertiesMapping = props.getProperty ("_properties"); String propertiesMapping = props.getProperty ("_properties");
if (propertiesMapping != null) { if (propertiesMapping != null) {
try { try {
propertiesRel = new Relation (propertiesMapping, "_properties", this, props); // check if property relation already exists. If so, reuse it
if (propertiesRel.isReference ()) if (propertiesRel == null)
properties = propertiesRel.other; propertiesRel = new Relation (propertiesMapping, "_properties", this, props);
else else
properties = (DbMapping) app.getDbMapping (propertiesMapping); propertiesRel.update (propertiesMapping, props);
// if (propertiesRel.isReference ())
// properties = propertiesRel.other;
// else
// properties = (DbMapping) app.getDbMapping (propertiesMapping);
// take over groupby flag from subnodes, if properties are subnodes // take over groupby flag from subnodes, if properties are subnodes
if (propertiesRel.subnodesAreProperties && subnodesRel != null) if (propertiesRel.subnodesAreProperties && subnodesRel != null)
propertiesRel.groupby = subnodesRel.groupby; propertiesRel.groupby = subnodesRel.groupby;
} catch (Exception x) { } catch (Exception x) {
app.logEvent ("Error in type.properties: "+x.getMessage ()); app.logEvent ("Error reading _properties relation for "+typename+": "+x.getMessage ());
propertiesRel = null; // propertiesRel = null;
} }
} else } else
propertiesRel = null; propertiesRel = null;
// app.logEvent ("rewiring: "+this); if (groupbyMapping != null) {
groupbyMapping.subnodesRel = subnodesRel == null ? null : subnodesRel.getGroupbySubnodeRelation ();
groupbyMapping.propertiesRel = propertiesRel == null ? null : propertiesRel.getGroupbyPropertyRelation ();
groupbyMapping.lastTypeChange = this.lastTypeChange;
}
} }
@ -323,21 +345,46 @@ public class DbMapping implements Updatable {
/** /**
* Translate a database column name to an object property name according to this mapping. * Translate a database column name to an object property name according to this mapping.
*/ */
public Relation columnNameToProperty (String columnName) { public String columnNameToProperty (String columnName) {
if (table == null && parentMapping != null) if (table == null && parentMapping != null)
return parentMapping.columnNameToProperty (columnName); return parentMapping.columnNameToProperty (columnName);
Relation rel = (Relation) db2prop.get (columnName);
if (rel != null && (rel.direction == Relation.PRIMITIVE || rel.direction == Relation.FORWARD))
return rel.propname;
return null;
}
/**
* Translate an object property name to a database column name according to this mapping.
*/
public String propertyToColumnName (String propName) {
if (table == null && parentMapping != null)
return parentMapping.propertyToColumnName (propName);
Relation rel = (Relation) prop2db.get (propName);
if (rel != null && (rel.direction == Relation.PRIMITIVE || rel.direction == Relation.FORWARD))
return rel.localField;
return null;
}
/**
* Translate a database column name to an object property name according to this mapping.
*/
public Relation columnNameToRelation (String columnName) {
if (table == null && parentMapping != null)
return parentMapping.columnNameToRelation (columnName);
return (Relation) db2prop.get (columnName); return (Relation) db2prop.get (columnName);
} }
/** /**
* Translate an object property name to a database column name according to this mapping. * Translate an object property name to a database column name according to this mapping.
*/ */
public Relation propertyToColumnName (String propName) { public Relation propertyToRelation (String propName) {
if (table == null && parentMapping != null) if (table == null && parentMapping != null)
return parentMapping.propertyToColumnName (propName); return parentMapping.propertyToRelation (propName);
return (Relation) prop2db.get (propName); return (Relation) prop2db.get (propName);
} }
public synchronized ParentInfo[] getParentInfo () { public synchronized ParentInfo[] getParentInfo () {
if (parent == null && parentMapping != null) if (parent == null && parentMapping != null)
return parentMapping.getParentInfo (); return parentMapping.getParentInfo ();
@ -346,14 +393,13 @@ public class DbMapping implements Updatable {
public DbMapping getSubnodeMapping () { public DbMapping getSubnodeMapping () {
if (subnodes == null && parentMapping != null) if (subnodesRel != null)
return subnodesRel.other;
if (parentMapping != null)
return parentMapping.getSubnodeMapping (); return parentMapping.getSubnodeMapping ();
return subnodes; return null;
} }
public void setSubnodeMapping (DbMapping sm) {
subnodes = sm;
}
public DbMapping getExactPropertyMapping (String propname) { public DbMapping getExactPropertyMapping (String propname) {
if (propname == null) if (propname == null)
@ -365,8 +411,13 @@ public class DbMapping implements Updatable {
} }
public DbMapping getPropertyMapping (String propname) { public DbMapping getPropertyMapping (String propname) {
if (propname == null) if (propname == null) {
return properties; if (propertiesRel != null)
return propertiesRel.other;
if (parentMapping != null)
return parentMapping.getPropertyMapping (null);
}
Relation rel = (Relation) prop2db.get (propname.toLowerCase()); Relation rel = (Relation) prop2db.get (propname.toLowerCase());
if (rel != null) { if (rel != null) {
// if this is a virtual node, it doesn't have a dbmapping // if this is a virtual node, it doesn't have a dbmapping
@ -376,16 +427,32 @@ public class DbMapping implements Updatable {
return rel.other; return rel.other;
} }
if (properties == null && parentMapping != null) if (propertiesRel != null)
return propertiesRel.other;
if (parentMapping != null)
return parentMapping.getPropertyMapping (propname); return parentMapping.getPropertyMapping (propname);
return null;
return properties;
} }
public void setPropertyMapping (DbMapping pm) { public DbMapping getGroupbyMapping () {
properties = pm; if (subnodesRel == null || subnodesRel.groupby == null)
return null;
if (groupbyMapping == null) {
groupbyMapping = new DbMapping ();
groupbyMapping.subnodesRel = subnodesRel.getGroupbySubnodeRelation ();
if (propertiesRel != null)
groupbyMapping.propertiesRel = propertiesRel.getGroupbyPropertyRelation ();
else
groupbyMapping.propertiesRel = subnodesRel.getGroupbyPropertyRelation ();
groupbyMapping.typename = subnodesRel.prototype;
}
return groupbyMapping;
} }
/* public void setPropertyMapping (DbMapping pm) {
properties = pm;
} */
public void setSubnodeRelation (Relation rel) { public void setSubnodeRelation (Relation rel) {
subnodesRel = rel; subnodesRel = rel;
} }

View file

@ -44,6 +44,15 @@ public class DbSource {
// false here and make commit/rollback invocations in Transactor methods; // false here and make commit/rollback invocations in Transactor methods;
IServer.getLogger().log ("Created new Connection to "+url); IServer.getLogger().log ("Created new Connection to "+url);
tx.registerConnection (this, con); tx.registerConnection (this, con);
//////////////////////////////////////////////
/* DatabaseMetaData meta = con.getMetaData ();
ResultSet tables = meta.getCatalogs ();
while (tables.next())
System.err.println ("********* TABLE: "+ tables.getObject (1));
ResultSet types = meta.getTypeInfo ();
while (types.next())
System.err.println ("******* TYPE: "+types.getObject(1) +" - "+types.getObject(2)+" - "+types.getObject(6));
*/
} }
return con; return con;
} }

View file

@ -393,9 +393,7 @@ public class Node implements INode, Serializable {
// node.setState (TRANSIENT); // node.setState (TRANSIENT);
// make a db mapping good enough that the virtual node finds its subnodes // make a db mapping good enough that the virtual node finds its subnodes
DbMapping dbm = new DbMapping (); DbMapping dbm = new DbMapping ();
dbm.setSubnodeMapping (rel.other);
dbm.setSubnodeRelation (rel); dbm.setSubnodeRelation (rel);
dbm.setPropertyMapping (rel.other);
dbm.setPropertyRelation (rel); dbm.setPropertyRelation (rel);
node.setDbMapping (dbm); node.setDbMapping (dbm);
setNode (propname, node); setNode (propname, node);

View file

@ -13,15 +13,27 @@ import java.util.Properties;
*/ */
public class Relation { public class Relation {
// TODO: explain hop mapping types // these constants define different type of property-to-db-mappings
// there is an error in the description of this relation
public final static int INVALID = -1; public final static int INVALID = -1;
// a mapping of a non-object, scalar type
public final static int PRIMITIVE = 0; public final static int PRIMITIVE = 0;
// a 1-to-1 relation, i.e. a field in the table is a foreign key to another object
public final static int FORWARD = 1; public final static int FORWARD = 1;
// a 1-to-many relation, a field in another table points to objects of this type
public final static int BACKWARD = 2; public final static int BACKWARD = 2;
// direct mapping is a very powerful feature: objects of some types can be directly accessed
// by one of their properties/db fields.
public final static int DIRECT = 3; public final static int DIRECT = 3;
// the DbMapping of the type we come from
public DbMapping home; public DbMapping home;
// the DbMapping of the prototype we link to, unless this is a "primitive" (non-object) relation
public DbMapping other; public DbMapping other;
// if this relation defines a virtual node, we need a DbMapping for these virtual nodes
DbMapping virtualMapping;
public String propname; public String propname;
protected String localField, remoteField; protected String localField, remoteField;
public int direction; public int direction;
@ -34,31 +46,39 @@ public class Relation {
public String order; public String order;
public String groupbyorder; public String groupbyorder;
public String groupby; public String groupby;
public String dogroupby;
public String prototype; public String prototype;
public String groupbyprototype; public String groupbyprototype;
public String filter; public String filter;
Relation subnoderelation = null; // additional relation used to filter subnodes Relation subnoderelation = null; // additional relation used to filter subnodes for virtual nodes
/** /**
* This constructor is used to directly construct a Relation, as opposed to reading it from a proerty file * This constructor makes a copy of an existing relation. Not all fields are copied, just those
* which are needed in groupby- and virtual nodes defined by this relation.
*/ */
public Relation (DbMapping other, String localField, String remoteField, int direction, boolean subnodesAreProperties) { public Relation (Relation rel) {
this.other = other; this.home = rel.home;
this.localField = localField; this.other = rel.other;
this.remoteField = remoteField; this.localField = rel.localField;
this.direction = direction; this.remoteField = rel.remoteField;
this.subnodesAreProperties = subnodesAreProperties; this.direction = rel.direction;
this.subnodesAreProperties = rel.subnodesAreProperties;
} }
/** /**
* Reads a relation entry from a line in a properties file. * Reads a relation entry from a line in a properties file.
*/ */
public Relation (String desc, String propname, DbMapping home, Properties props) { public Relation (String desc, String propname, DbMapping home, Properties props) {
this.home = home; this.home = home;
this.propname = propname; this.propname = propname;
other = null; other = null;
update (desc, props);
}
public void update (String desc, Properties props) {
Application app = home.getApplication (); Application app = home.getApplication ();
boolean mountpoint = false; boolean mountpoint = false;
@ -179,6 +199,12 @@ public class Relation {
subnoderelation.order = order; subnoderelation.order = order;
} }
} }
// update virtual mapping, if it already exists
if (virtualMapping != null) {
virtualMapping.subnodesRel = getVirtualSubnodeRelation ();
virtualMapping.propertiesRel = getVirtualPropertyRelation ();
virtualMapping.lastTypeChange = home.lastTypeChange;
}
} }
} }
} }
@ -200,23 +226,6 @@ public class Relation {
return subnoderelation; return subnoderelation;
} }
/**
* Gets a key string to cache a node with a specific value for this relation. If the
* Relation uses the primary key return just the key value, otherwise include info on the
* used column or even the base node to avoid collisions.
*/
/* public String getKeyID (INode home, String kval) {
// if the column is not the primary key, we add the column name to the key
if ((direction == DIRECT || direction == FORWARD) && !usesPrimaryKey ()) {
// check if the subnode relation also has to be considered
if (subnodesAreProperties)
return "["+home.getID()+"]"+remoteField+"="+kval; // HACK
else
return remoteField+"="+kval;
} else {
return kval;
}
} */
/** /**
* Get the local column name for this relation to use in where clauses of select statements. * Get the local column name for this relation to use in where clauses of select statements.
@ -247,18 +256,29 @@ public class Relation {
return remoteField; return remoteField;
} }
public DbMapping getVirtualMapping () {
if (!virtual)
return null;
if (virtualMapping == null) {
virtualMapping = new DbMapping ();
virtualMapping.subnodesRel = getVirtualSubnodeRelation ();
virtualMapping.propertiesRel = getVirtualPropertyRelation ();
}
return virtualMapping;
}
/** /**
* Return a Relation that defines the subnodes of a virtual node. * Return a Relation that defines the subnodes of a virtual node.
*/ */
public Relation getVirtualSubnodeRelation () { Relation getVirtualSubnodeRelation () {
if (!virtual) if (!virtual)
throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation"); throw new RuntimeException ("getVirtualSubnodeRelation called on non-virtual relation");
Relation vr = null; Relation vr = null;
if (subnoderelation != null) if (subnoderelation != null)
vr = subnoderelation.makeClone (); vr = new Relation (subnoderelation);
else else
vr = makeClone (); vr = new Relation (this);
vr.groupby = groupby; vr.groupby = groupby;
vr.groupbyorder = groupbyorder; vr.groupbyorder = groupbyorder;
vr.groupbyprototype = groupbyprototype; vr.groupbyprototype = groupbyprototype;
@ -273,10 +293,10 @@ public class Relation {
/** /**
* Return a Relation that defines the properties of a virtual node. * Return a Relation that defines the properties of a virtual node.
*/ */
public Relation getVirtualPropertyRelation () { Relation getVirtualPropertyRelation () {
if (!virtual) if (!virtual)
throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation"); throw new RuntimeException ("getVirtualPropertyRelation called on non-virtual relation");
Relation vr = makeClone (); Relation vr = new Relation (this);
vr.groupby = groupby; vr.groupby = groupby;
vr.groupbyorder = groupbyorder; vr.groupbyorder = groupbyorder;
vr.groupbyprototype = groupbyprototype; vr.groupbyprototype = groupbyprototype;
@ -289,37 +309,35 @@ public class Relation {
/** /**
* Return a Relation that defines the subnodes of a group-by node. * Return a Relation that defines the subnodes of a group-by node.
*/ */
public Relation getGroupbySubnodeRelation () { Relation getGroupbySubnodeRelation () {
if (groupby == null) if (groupby == null)
throw new RuntimeException ("getGroupbySubnodeRelation called on non-group-by relation"); throw new RuntimeException ("getGroupbySubnodeRelation called on non-group-by relation");
Relation vr = null; Relation vr = null;
if (subnoderelation != null) if (subnoderelation != null)
vr = subnoderelation.makeClone (); vr = new Relation (subnoderelation);
else else
vr = makeClone (); vr = new Relation (this);
vr.order = order; vr.order = order;
vr.prototype = groupbyprototype; vr.prototype = groupbyprototype;
vr.filter = filter; vr.filter = filter;
vr.dogroupby = groupby;
return vr; return vr;
} }
/** /**
* Return a Relation that defines the properties of a group-by node. * Return a Relation that defines the properties of a group-by node.
*/ */
public Relation getGroupbyPropertyRelation () { Relation getGroupbyPropertyRelation () {
if (groupby == null) if (groupby == null)
throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation"); throw new RuntimeException ("getGroupbyPropertyRelation called on non-group-by relation");
Relation vr = makeClone (); Relation vr = new Relation (this);
vr.order = order; vr.order = order;
vr.prototype = groupbyprototype; vr.prototype = groupbyprototype;
vr.filter = filter; vr.filter = filter;
vr.dogroupby = groupby;
return vr; return vr;
} }
public Relation makeClone () {
return new Relation (other, localField, remoteField, direction, subnodesAreProperties);
}
public String toString () { public String toString () {
return "Relation["+home+">"+other+"]"; return "Relation["+home+">"+other+"]";