* Use explicit list of columns in select statement.

* Only care and know about columns that are mapped or used internally.
* Fixed bug in size() for grouped collections with loadmode=aggressive.
This commit is contained in:
hns 2003-05-22 11:08:04 +00:00
parent 1f38513443
commit 5c192c437a
3 changed files with 127 additions and 57 deletions

View file

@ -26,10 +26,16 @@ public final class DbColumn {
private final int type;
private final Relation relation;
private final boolean isId;
private final boolean isPrototype;
private final boolean isName;
private final boolean isMapped;
/**
* Constructor
*/
public DbColumn(String name, int type, Relation rel) {
public DbColumn(String name, int type, Relation rel, DbMapping dbmap) {
this.name = name;
this.type = type;
this.relation = rel;
@ -37,6 +43,12 @@ public final class DbColumn {
if (relation != null) {
relation.setColumnType(type);
}
isId = name.equalsIgnoreCase(dbmap.getIDField());
isPrototype = name.equalsIgnoreCase(dbmap.getPrototypeField());
isName = name.equalsIgnoreCase(dbmap.getNameField());
isMapped = relation != null || isId || isPrototype || isName;
}
/**
@ -59,4 +71,33 @@ public final class DbColumn {
public Relation getRelation() {
return relation;
}
/**
* Returns true if this column serves as ID field for the prototype.
*/
public boolean isIdField() {
return isId;
}
/**
* Returns true if this column serves as prototype field for the prototype.
*/
public boolean isPrototypeField() {
return isPrototype;
}
/**
* Returns true if this column serves as name field for the prototype.
*/
public boolean isNameField() {
return isName;
}
/**
* Returns true if this field is mapped by the prototype's db mapping.
*/
public boolean isMapped() {
return isMapped;
}
}

View file

@ -24,6 +24,7 @@ import java.sql.*;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;
@ -836,16 +837,20 @@ public final class DbMapping implements Updatable {
// ok, we have the meta data, now loop through mapping...
int ncols = meta.getColumnCount();
columns = new DbColumn[ncols];
ArrayList list = new ArrayList(ncols);
for (int i = 0; i < ncols; i++) {
String colName = meta.getColumnName(i + 1);
Relation rel = columnNameToRelation(colName);
columns[i] = new DbColumn(colName, meta.getColumnType(i + 1), rel);
DbColumn col = new DbColumn(colName, meta.getColumnType(i + 1), rel, this);
if (col.isMapped()) {
list.add(col);
}
}
columns = new DbColumn[list.size()];
columns = (DbColumn[]) list.toArray(columns);
}
return columns;
}
@ -862,6 +867,7 @@ public final class DbMapping implements Updatable {
*/
public DbColumn getColumn(String columnName)
throws ClassNotFoundException, SQLException {
DbColumn col = (DbColumn) columnMap.get(columnName);
if (col == null) {
@ -879,10 +885,6 @@ public final class DbMapping implements Updatable {
}
}
if (col == null) {
throw new SQLException("Column " + columnName + " not found in " + this);
}
columnMap.put(columnName, col);
}
@ -890,12 +892,13 @@ public final class DbMapping implements Updatable {
}
/**
* Get a StringBuffer initialized to the first part of the select statement
* for objects defined by this DbMapping
*
* @return the StringBuffer containing the first part of the select query
*
* @return ...
*
* @throws SQLException ...
* @throws ClassNotFoundException ...
* @throws SQLException if the table meta data could not be retrieved
* @throws ClassNotFoundException if the JDBC driver class was not found
*/
public StringBuffer getSelect() throws SQLException, ClassNotFoundException {
String sel = selectString;
@ -904,7 +907,22 @@ public final class DbMapping implements Updatable {
return new StringBuffer(sel);
}
StringBuffer s = new StringBuffer("SELECT * FROM ");
StringBuffer s = new StringBuffer("SELECT ");
DbColumn[] cols = columns;
if (cols == null) {
cols = getColumns();
}
for (int i = 0; i < cols.length; i++) {
s.append(cols[i].getName());
if (i < cols.length-1) {
s.append(',');
}
}
s.append(" FROM ");
s.append(getTableName());
s.append(" ");
@ -974,6 +992,11 @@ public final class DbMapping implements Updatable {
try {
DbColumn col = getColumn(columnName);
// This is not a mapped column. In case of doubt, add quotes.
if (col == null) {
return true;
}
switch (col.getType()) {
case Types.CHAR:
case Types.VARCHAR:

View file

@ -154,10 +154,13 @@ public final class Node implements INode, Serializable {
// see what prototype/DbMapping this object should use
dbmap = dbm;
String protoField = dbmap.getPrototypeField();
created = lastmodified = System.currentTimeMillis();
if (protoField != null) {
String protoName = rs.getString(protoField);
for (int i = 0; i < columns.length; i++) {
// set prototype?
if (columns[i].isPrototypeField()) {
String protoName = rs.getString(i+1);
if (protoName != null) {
dbmap = nmgr.getDbMapping(protoName);
@ -171,22 +174,16 @@ public final class Node implements INode, Serializable {
}
}
setPrototype(dbmap.getTypeName());
id = rs.getString(dbmap.getIDField());
// checkWriteLock ();
String nameField = dbmap.getNameField();
name = (nameField == null) ? id : rs.getString(nameField);
if ((name == null) || (name.length() == 0)) {
name = dbmap.getTypeName() + " " + id;
// set id?
if (columns[i].isIdField()) {
id = rs.getString(i+1);
}
created = lastmodified = System.currentTimeMillis();
// set name?
if (columns[i].isNameField()) {
name = rs.getString(i+1);
}
for (int i = 0; i < columns.length; i++) {
Relation rel = columns[i].getRelation();
if ((rel == null) ||
@ -199,7 +196,7 @@ public final class Node implements INode, Serializable {
switch (columns[i].getType()) {
case Types.BIT:
newprop.setBooleanValue(rs.getBoolean(columns[i].getName()));
newprop.setBooleanValue(rs.getBoolean(i+1));
break;
@ -207,21 +204,21 @@ public final class Node implements INode, Serializable {
case Types.BIGINT:
case Types.SMALLINT:
case Types.INTEGER:
newprop.setIntegerValue(rs.getLong(columns[i].getName()));
newprop.setIntegerValue(rs.getLong(i+1));
break;
case Types.REAL:
case Types.FLOAT:
case Types.DOUBLE:
newprop.setFloatValue(rs.getDouble(columns[i].getName()));
newprop.setFloatValue(rs.getDouble(i+1));
break;
case Types.DECIMAL:
case Types.NUMERIC:
BigDecimal num = rs.getBigDecimal(columns[i].getName());
BigDecimal num = rs.getBigDecimal(i+1);
if (num == null) {
break;
@ -237,7 +234,7 @@ public final class Node implements INode, Serializable {
case Types.VARBINARY:
case Types.BINARY:
newprop.setStringValue(rs.getString(columns[i].getName()));
newprop.setStringValue(rs.getString(i+1));
break;
@ -245,9 +242,9 @@ public final class Node implements INode, Serializable {
case Types.LONGVARCHAR:
try {
newprop.setStringValue(rs.getString(columns[i].getName()));
newprop.setStringValue(rs.getString(i+1));
} catch (SQLException x) {
Reader in = rs.getCharacterStream(columns[i].getName());
Reader in = rs.getCharacterStream(i+1);
char[] buffer = new char[2048];
int read = 0;
int r = 0;
@ -272,22 +269,22 @@ public final class Node implements INode, Serializable {
case Types.CHAR:
case Types.VARCHAR:
case Types.OTHER:
newprop.setStringValue(rs.getString(columns[i].getName()));
newprop.setStringValue(rs.getString(i+1));
break;
case Types.DATE:
newprop.setDateValue(rs.getDate(columns[i].getName()));
newprop.setDateValue(rs.getDate(i+1));
break;
case Types.TIME:
newprop.setDateValue(rs.getTime(columns[i].getName()));
newprop.setDateValue(rs.getTime(i+1));
break;
case Types.TIMESTAMP:
newprop.setDateValue(rs.getTimestamp(columns[i].getName()));
newprop.setDateValue(rs.getTimestamp(i+1));
break;
@ -298,7 +295,7 @@ public final class Node implements INode, Serializable {
// continue;
default:
newprop.setStringValue(rs.getString(columns[i].getName()));
newprop.setStringValue(rs.getString(i+1));
break;
}
@ -326,6 +323,15 @@ public final class Node implements INode, Serializable {
newprop.dirty = false;
}
// set the prototype from the dbmap,
// which was possibly modified while reading the resultset
setPrototype(dbmap.getTypeName());
// If name was not set from resultset, create a synthetical name now.
if ((name == null) || (name.length() == 0)) {
name = dbmap.getTypeName() + " " + id;
}
// again set created and lastmodified. This is because
// lastmodified has been been updated, and we want both values to
// be identical to show that the node hasn't been changed since
@ -1585,7 +1591,7 @@ public final class Node implements INode, Serializable {
// do not fetch subnodes for nodes that haven't been persisted yet or are in
// the process of being persistified - except if "manual" subnoderelation is set.
if (subRel.aggressiveLoading &&
if (subRel.aggressiveLoading && subRel.getGroup() == null &&
(((state != TRANSIENT) && (state != NEW)) ||
(subnodeRelation != null))) {
// we don't want to load *all* nodes if we just want to count them