* 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 int type;
|
||||||
private final Relation relation;
|
private final Relation relation;
|
||||||
|
|
||||||
|
private final boolean isId;
|
||||||
|
private final boolean isPrototype;
|
||||||
|
private final boolean isName;
|
||||||
|
|
||||||
|
private final boolean isMapped;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public DbColumn(String name, int type, Relation rel) {
|
public DbColumn(String name, int type, Relation rel, DbMapping dbmap) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.relation = rel;
|
this.relation = rel;
|
||||||
|
@ -37,6 +43,12 @@ public final class DbColumn {
|
||||||
if (relation != null) {
|
if (relation != null) {
|
||||||
relation.setColumnType(type);
|
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() {
|
public Relation getRelation() {
|
||||||
return relation;
|
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.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
@ -836,15 +837,19 @@ public final class DbMapping implements Updatable {
|
||||||
|
|
||||||
// ok, we have the meta data, now loop through mapping...
|
// ok, we have the meta data, now loop through mapping...
|
||||||
int ncols = meta.getColumnCount();
|
int ncols = meta.getColumnCount();
|
||||||
|
ArrayList list = new ArrayList(ncols);
|
||||||
columns = new DbColumn[ncols];
|
|
||||||
|
|
||||||
for (int i = 0; i < ncols; i++) {
|
for (int i = 0; i < ncols; i++) {
|
||||||
String colName = meta.getColumnName(i + 1);
|
String colName = meta.getColumnName(i + 1);
|
||||||
Relation rel = columnNameToRelation(colName);
|
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;
|
return columns;
|
||||||
|
@ -862,6 +867,7 @@ public final class DbMapping implements Updatable {
|
||||||
*/
|
*/
|
||||||
public DbColumn getColumn(String columnName)
|
public DbColumn getColumn(String columnName)
|
||||||
throws ClassNotFoundException, SQLException {
|
throws ClassNotFoundException, SQLException {
|
||||||
|
|
||||||
DbColumn col = (DbColumn) columnMap.get(columnName);
|
DbColumn col = (DbColumn) columnMap.get(columnName);
|
||||||
|
|
||||||
if (col == null) {
|
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);
|
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 if the table meta data could not be retrieved
|
||||||
*
|
* @throws ClassNotFoundException if the JDBC driver class was not found
|
||||||
* @throws SQLException ...
|
|
||||||
* @throws ClassNotFoundException ...
|
|
||||||
*/
|
*/
|
||||||
public StringBuffer getSelect() throws SQLException, ClassNotFoundException {
|
public StringBuffer getSelect() throws SQLException, ClassNotFoundException {
|
||||||
String sel = selectString;
|
String sel = selectString;
|
||||||
|
@ -904,7 +907,22 @@ public final class DbMapping implements Updatable {
|
||||||
return new StringBuffer(sel);
|
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(getTableName());
|
||||||
s.append(" ");
|
s.append(" ");
|
||||||
|
@ -974,6 +992,11 @@ public final class DbMapping implements Updatable {
|
||||||
try {
|
try {
|
||||||
DbColumn col = getColumn(columnName);
|
DbColumn col = getColumn(columnName);
|
||||||
|
|
||||||
|
// This is not a mapped column. In case of doubt, add quotes.
|
||||||
|
if (col == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (col.getType()) {
|
switch (col.getType()) {
|
||||||
case Types.CHAR:
|
case Types.CHAR:
|
||||||
case Types.VARCHAR:
|
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.
|
* Constructor used for nodes being stored in a relational database table.
|
||||||
*/
|
*/
|
||||||
public Node(DbMapping dbm, ResultSet rs, DbColumn[] columns, WrappedNodeManager nmgr)
|
public Node(DbMapping dbm, ResultSet rs, DbColumn[] columns, WrappedNodeManager nmgr)
|
||||||
throws SQLException, IOException {
|
throws SQLException, IOException {
|
||||||
this.nmgr = nmgr;
|
this.nmgr = nmgr;
|
||||||
|
|
||||||
// see what prototype/DbMapping this object should use
|
// see what prototype/DbMapping this object should use
|
||||||
dbmap = dbm;
|
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();
|
created = lastmodified = System.currentTimeMillis();
|
||||||
|
|
||||||
for (int i = 0; i < columns.length; i++) {
|
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();
|
Relation rel = columns[i].getRelation();
|
||||||
|
|
||||||
if ((rel == null) ||
|
if ((rel == null) ||
|
||||||
|
@ -199,7 +196,7 @@ public final class Node implements INode, Serializable {
|
||||||
|
|
||||||
switch (columns[i].getType()) {
|
switch (columns[i].getType()) {
|
||||||
case Types.BIT:
|
case Types.BIT:
|
||||||
newprop.setBooleanValue(rs.getBoolean(columns[i].getName()));
|
newprop.setBooleanValue(rs.getBoolean(i+1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -207,21 +204,21 @@ public final class Node implements INode, Serializable {
|
||||||
case Types.BIGINT:
|
case Types.BIGINT:
|
||||||
case Types.SMALLINT:
|
case Types.SMALLINT:
|
||||||
case Types.INTEGER:
|
case Types.INTEGER:
|
||||||
newprop.setIntegerValue(rs.getLong(columns[i].getName()));
|
newprop.setIntegerValue(rs.getLong(i+1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.REAL:
|
case Types.REAL:
|
||||||
case Types.FLOAT:
|
case Types.FLOAT:
|
||||||
case Types.DOUBLE:
|
case Types.DOUBLE:
|
||||||
newprop.setFloatValue(rs.getDouble(columns[i].getName()));
|
newprop.setFloatValue(rs.getDouble(i+1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.DECIMAL:
|
case Types.DECIMAL:
|
||||||
case Types.NUMERIC:
|
case Types.NUMERIC:
|
||||||
|
|
||||||
BigDecimal num = rs.getBigDecimal(columns[i].getName());
|
BigDecimal num = rs.getBigDecimal(i+1);
|
||||||
|
|
||||||
if (num == null) {
|
if (num == null) {
|
||||||
break;
|
break;
|
||||||
|
@ -237,7 +234,7 @@ public final class Node implements INode, Serializable {
|
||||||
|
|
||||||
case Types.VARBINARY:
|
case Types.VARBINARY:
|
||||||
case Types.BINARY:
|
case Types.BINARY:
|
||||||
newprop.setStringValue(rs.getString(columns[i].getName()));
|
newprop.setStringValue(rs.getString(i+1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -245,9 +242,9 @@ public final class Node implements INode, Serializable {
|
||||||
case Types.LONGVARCHAR:
|
case Types.LONGVARCHAR:
|
||||||
|
|
||||||
try {
|
try {
|
||||||
newprop.setStringValue(rs.getString(columns[i].getName()));
|
newprop.setStringValue(rs.getString(i+1));
|
||||||
} catch (SQLException x) {
|
} catch (SQLException x) {
|
||||||
Reader in = rs.getCharacterStream(columns[i].getName());
|
Reader in = rs.getCharacterStream(i+1);
|
||||||
char[] buffer = new char[2048];
|
char[] buffer = new char[2048];
|
||||||
int read = 0;
|
int read = 0;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
@ -272,22 +269,22 @@ public final class Node implements INode, Serializable {
|
||||||
case Types.CHAR:
|
case Types.CHAR:
|
||||||
case Types.VARCHAR:
|
case Types.VARCHAR:
|
||||||
case Types.OTHER:
|
case Types.OTHER:
|
||||||
newprop.setStringValue(rs.getString(columns[i].getName()));
|
newprop.setStringValue(rs.getString(i+1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.DATE:
|
case Types.DATE:
|
||||||
newprop.setDateValue(rs.getDate(columns[i].getName()));
|
newprop.setDateValue(rs.getDate(i+1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.TIME:
|
case Types.TIME:
|
||||||
newprop.setDateValue(rs.getTime(columns[i].getName()));
|
newprop.setDateValue(rs.getTime(i+1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Types.TIMESTAMP:
|
case Types.TIMESTAMP:
|
||||||
newprop.setDateValue(rs.getTimestamp(columns[i].getName()));
|
newprop.setDateValue(rs.getTimestamp(i+1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -298,7 +295,7 @@ public final class Node implements INode, Serializable {
|
||||||
|
|
||||||
// continue;
|
// continue;
|
||||||
default:
|
default:
|
||||||
newprop.setStringValue(rs.getString(columns[i].getName()));
|
newprop.setStringValue(rs.getString(i+1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -326,6 +323,15 @@ public final class Node implements INode, Serializable {
|
||||||
newprop.dirty = false;
|
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
|
// again set created and lastmodified. This is because
|
||||||
// lastmodified has been been updated, and we want both values to
|
// lastmodified has been been updated, and we want both values to
|
||||||
// be identical to show that the node hasn't been changed since
|
// 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
|
// 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.
|
// the process of being persistified - except if "manual" subnoderelation is set.
|
||||||
if (subRel.aggressiveLoading &&
|
if (subRel.aggressiveLoading && subRel.getGroup() == null &&
|
||||||
(((state != TRANSIENT) && (state != NEW)) ||
|
(((state != TRANSIENT) && (state != NEW)) ||
|
||||||
(subnodeRelation != null))) {
|
(subnodeRelation != null))) {
|
||||||
// we don't want to load *all* nodes if we just want to count them
|
// we don't want to load *all* nodes if we just want to count them
|
||||||
|
|
Loading…
Add table
Reference in a new issue