* 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:
parent
1f38513443
commit
5c192c437a
3 changed files with 127 additions and 57 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,15 +837,19 @@ 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:
|
||||
|
|
|
@ -148,45 +148,42 @@ public final class Node implements INode, Serializable {
|
|||
* Constructor used for nodes being stored in a relational database table.
|
||||
*/
|
||||
public Node(DbMapping dbm, ResultSet rs, DbColumn[] columns, WrappedNodeManager nmgr)
|
||||
throws SQLException, IOException {
|
||||
throws SQLException, IOException {
|
||||
this.nmgr = nmgr;
|
||||
|
||||
// see what prototype/DbMapping this object should use
|
||||
dbmap = dbm;
|
||||
|
||||
String protoField = dbmap.getPrototypeField();
|
||||
|
||||
if (protoField != null) {
|
||||
String protoName = rs.getString(protoField);
|
||||
|
||||
if (protoName != null) {
|
||||
dbmap = nmgr.getDbMapping(protoName);
|
||||
|
||||
if (dbmap == null) {
|
||||
// invalid prototype name!
|
||||
System.err.println("Warning: Invalid prototype name: " + protoName +
|
||||
" - using default");
|
||||
dbmap = dbm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
created = lastmodified = System.currentTimeMillis();
|
||||
|
||||
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);
|
||||
|
||||
if (dbmap == null) {
|
||||
// invalid prototype name!
|
||||
System.err.println("Warning: Invalid prototype name: " + protoName +
|
||||
" - using default");
|
||||
dbmap = dbm;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set id?
|
||||
if (columns[i].isIdField()) {
|
||||
id = rs.getString(i+1);
|
||||
}
|
||||
|
||||
// set name?
|
||||
if (columns[i].isNameField()) {
|
||||
name = rs.getString(i+1);
|
||||
}
|
||||
|
||||
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
|
||||
|
|
Loading…
Add table
Reference in a new issue