use of org.datanucleus.metadata.RelationType in project datanucleus-core by datanucleus.
the class JavaQueryCompiler method getClassForSubqueryClassExpression.
/**
* Convenience method to find the class that a subquery class expression refers to.
* Allows for reference to the parent query candidate class, or to a class name.
* @param classExpr The class expression
* @return The class that it refers to
*/
private Class getClassForSubqueryClassExpression(String classExpr) {
if (classExpr == null) {
return null;
}
Class cls = null;
String[] tokens = StringUtils.split(classExpr, ".");
if (tokens[0].equalsIgnoreCase(parentCompiler.candidateAlias)) {
// Starts with candidate of parent query
cls = parentCompiler.candidateClass;
} else {
// Try alias from parent query
Symbol sym = parentCompiler.symtbl.getSymbolIgnoreCase(tokens[0]);
if (sym != null) {
cls = sym.getValueType();
} else {
// Must be a class name
return resolveClass(classExpr);
}
}
AbstractClassMetaData cmd = metaDataManager.getMetaDataForClass(cls, clr);
for (int i = 1; i < tokens.length; i++) {
AbstractMemberMetaData mmd = cmd.getMetaDataForMember(tokens[i]);
RelationType relationType = mmd.getRelationType(clr);
if (RelationType.isRelationSingleValued(relationType)) {
cls = mmd.getType();
} else if (RelationType.isRelationMultiValued(relationType)) {
if (mmd.hasCollection()) {
cls = clr.classForName(mmd.getCollection().getElementType());
} else if (mmd.hasMap()) {
// Assume we're using the value
cls = clr.classForName(mmd.getMap().getValueType());
} else if (mmd.hasArray()) {
cls = clr.classForName(mmd.getArray().getElementType());
}
}
if (i < tokens.length - 1) {
cmd = metaDataManager.getMetaDataForClass(cls, clr);
}
}
return cls;
}
use of org.datanucleus.metadata.RelationType in project datanucleus-core by datanucleus.
the class JavaQueryCompiler method compileFrom.
/**
* Method to compile the "from" clause (if present for the query language).
* @return The compiled from expression(s)
*/
protected Expression[] compileFrom() {
if (from == null) {
return null;
}
Node[] node = parser.parseFrom(from);
Expression[] expr = new Expression[node.length];
for (int i = 0; i < node.length; i++) {
String className = (String) node[i].getNodeValue();
String classAlias = null;
Class cls = null;
if (parentCompiler != null) {
cls = getClassForSubqueryClassExpression(className);
} else {
cls = resolveClass(className);
}
List<Node> children = node[i].getChildNodes();
for (Node child : children) {
if (// Alias - maybe should assume it is the first child
child.getNodeType() == NodeType.NAME) {
classAlias = (String) child.getNodeValue();
}
}
if (i == 0 && classAlias == null) {
throw new QueryCompilerSyntaxException("FROM clause of query has class " + cls.getName() + " but no alias");
}
if (classAlias != null) {
if (i == 0) {
// First expression so set up candidateClass/alias
candidateClass = cls;
if (parentCompiler != null && parentCompiler.candidateAlias.equals(classAlias)) {
// The defined alias is the same as the parent query, so rename
candidateAliasOrig = classAlias;
candidateAlias = "sub_" + candidateAlias;
classAlias = candidateAlias;
swapCandidateAliasNodeName(node[i].getChildNode(0));
} else {
candidateAlias = classAlias;
}
}
if (symtbl.getSymbol(classAlias) == null) {
// Add symbol for this candidate under its alias
symtbl.addSymbol(new PropertySymbol(classAlias, cls));
}
}
for (Node childNode : children) {
// Add entries in symbol table for any joined aliases
if (childNode.getNodeType() == NodeType.OPERATOR) {
Node joinedNode = childNode.getFirstChild();
// Extract alias node
Node aliasNode = childNode.getNextChild();
// Extract ON node (if present)
Node onExprNode = null;
if (childNode.hasNextChild()) {
onExprNode = childNode.getNextChild();
}
String joinedAlias = (String) joinedNode.getNodeValue();
boolean rootNode = false;
Symbol joinedSym = caseSensitiveAliases ? symtbl.getSymbol(joinedAlias) : symtbl.getSymbolIgnoreCase(joinedAlias);
if (joinedSym == null) {
// DN Extension : Check for FROM clause including join to a new root
if (aliasNode != null) {
joinedAlias = (String) aliasNode.getNodeValue();
cls = resolveClass((String) joinedNode.getNodeValue());
if (symtbl.getSymbol(joinedAlias) == null) {
// Add symbol for this candidate under its alias
symtbl.addSymbol(new PropertySymbol(joinedAlias, cls));
rootNode = true;
NucleusLogger.QUERY.debug("Found suspected ROOT node joined to in FROM clause : attempting to process as alias=" + joinedAlias);
}
joinedSym = caseSensitiveAliases ? symtbl.getSymbol(joinedAlias) : symtbl.getSymbolIgnoreCase(joinedAlias);
}
if (joinedSym == null) {
throw new QueryCompilerSyntaxException("FROM clause has identifier " + joinedNode.getNodeValue() + " but this is unknown");
}
}
if (!rootNode) {
AbstractClassMetaData joinedCmd = metaDataManager.getMetaDataForClass(joinedSym.getValueType(), clr);
Class joinedCls = joinedSym.getValueType();
AbstractMemberMetaData joinedMmd = null;
while (joinedNode.getFirstChild() != null) {
joinedNode = joinedNode.getFirstChild();
String joinedMember = (String) joinedNode.getNodeValue();
if (joinedNode.getNodeType() == NodeType.CAST) {
// JOIN to "TREAT(identifier AS subcls)"
String castTypeName = (String) joinedNode.getNodeValue();
if (castTypeName.indexOf('.') < 0) {
// Fully-qualify with the current class name?
castTypeName = ClassUtils.createFullClassName(joinedCmd.getPackageName(), castTypeName);
}
joinedCls = clr.classForName(castTypeName);
// Update cast type now that we have resolved it
joinedNode.setNodeValue(castTypeName);
} else {
// Allow for multi-field joins
String[] joinedMembers = joinedMember.contains(".") ? StringUtils.split(joinedMember, ".") : new String[] { joinedMember };
for (int k = 0; k < joinedMembers.length; k++) {
String memberName = joinedMembers[k];
if (joinedCmd == null) {
throw new NucleusUserException("Query has JOIN to " + memberName + " but previous element (" + joinedCls.getName() + ") has no metadata");
}
if (memberName.endsWith("#KEY")) {
memberName = memberName.substring(0, memberName.length() - 4);
} else if (memberName.endsWith("#VALUE")) {
memberName = memberName.substring(0, memberName.length() - 6);
}
AbstractMemberMetaData mmd = joinedCmd.getMetaDataForMember(memberName);
if (mmd == null) {
if (childNode.getNodeValue().equals(JOIN_OUTER) || childNode.getNodeValue().equals(JOIN_OUTER_FETCH)) {
// Polymorphic join, where the field exists in a subclass (doable since we have outer join)
String[] subclasses = metaDataManager.getSubclassesForClass(joinedCmd.getFullClassName(), true);
if (subclasses != null) {
for (int l = 0; l < subclasses.length; l++) {
AbstractClassMetaData subCmd = metaDataManager.getMetaDataForClass(subclasses[l], clr);
if (subCmd != null) {
mmd = subCmd.getMetaDataForMember(memberName);
if (mmd != null) {
NucleusLogger.QUERY.debug("Polymorphic join found at " + memberName + " of " + subCmd.getFullClassName());
joinedCmd = subCmd;
break;
}
}
}
}
}
if (mmd == null) {
throw new QueryCompilerSyntaxException("FROM clause has reference to " + joinedCmd.getFullClassName() + "." + joinedMembers[k] + " but it doesn't exist!");
}
}
RelationType relationType = mmd.getRelationType(clr);
joinedMmd = mmd;
if (RelationType.isRelationSingleValued(relationType)) {
joinedCls = mmd.getType();
joinedCmd = metaDataManager.getMetaDataForClass(joinedCls, clr);
} else if (RelationType.isRelationMultiValued(relationType)) {
if (mmd.hasCollection()) {
// TODO Don't currently allow interface field navigation
joinedCmd = mmd.getCollection().getElementClassMetaData(clr);
if (joinedCmd != null) {
joinedCls = clr.classForName(joinedCmd.getFullClassName());
} else {
joinedCls = clr.classForName(mmd.getCollection().getElementType());
}
} else if (mmd.hasMap()) {
if (joinedMembers[k].endsWith("#KEY")) {
joinedCmd = mmd.getMap().getKeyClassMetaData(clr);
// TODO Set joinedCls
} else {
joinedCmd = mmd.getMap().getValueClassMetaData(clr);
if (joinedCmd != null) {
// JPA assumption that the value is an entity ... but it may not be!
joinedCls = clr.classForName(joinedCmd.getFullClassName());
} else {
joinedCls = clr.classForName(mmd.getMap().getValueType());
}
}
} else if (mmd.hasArray()) {
// TODO Don't currently allow interface field navigation
joinedCmd = mmd.getArray().getElementClassMetaData(clr);
if (joinedCmd != null) {
joinedCls = clr.classForName(joinedCmd.getFullClassName());
} else {
joinedCls = clr.classForName(mmd.getArray().getElementType());
}
}
}
}
}
}
if (aliasNode != null && aliasNode.getNodeType() == NodeType.NAME) {
// Add JOIN alias to symbol table
String alias = (String) aliasNode.getNodeValue();
symtbl.addSymbol(new PropertySymbol(alias, joinedCls));
if (joinedMmd != null && joinedMmd.hasMap()) {
Class keyCls = clr.classForName(joinedMmd.getMap().getKeyType());
// Add the KEY so that we can have joins to the key from the value alias
symtbl.addSymbol(new PropertySymbol(alias + "#KEY", keyCls));
Class valueCls = clr.classForName(joinedMmd.getMap().getValueType());
// Add the VALUE so that we can have joins to the value from the key alias
symtbl.addSymbol(new PropertySymbol(alias + "#VALUE", valueCls));
}
}
}
if (onExprNode != null) {
// ON condition
ExpressionCompiler comp = new ExpressionCompiler();
comp.setSymbolTable(symtbl);
comp.setMethodAliases(queryMgr.getQueryMethodAliasesByPrefix());
Expression nextExpr = comp.compileExpression(onExprNode);
nextExpr.bind(symtbl);
}
}
}
boolean classIsExpression = false;
String[] tokens = StringUtils.split(className, ".");
if (symtbl.getParentSymbolTable() != null) {
if (symtbl.getParentSymbolTable().hasSymbol(tokens[0])) {
classIsExpression = true;
}
}
ExpressionCompiler comp = new ExpressionCompiler();
comp.setSymbolTable(symtbl);
comp.setMethodAliases(queryMgr.getQueryMethodAliasesByPrefix());
expr[i] = comp.compileFromExpression(node[i], classIsExpression);
if (expr[i] != null) {
expr[i].bind(symtbl);
}
}
return expr;
}
use of org.datanucleus.metadata.RelationType in project datanucleus-rdbms by datanucleus.
the class CollectionTable method initialize.
/**
* Method to initialise the table definition.
* @param clr The ClassLoaderResolver
*/
public void initialize(ClassLoaderResolver clr) {
super.initialize(clr);
// Add column(s) for element
boolean elementPC = (mmd.hasCollection() && mmd.getCollection().elementIsPersistent());
Class elementClass = clr.classForName(getElementType());
if (isSerialisedElement() || isEmbeddedElementPC() || (isEmbeddedElement() && !elementPC) || ClassUtils.isReferenceType(elementClass)) {
// Element = PC(embedded), PC(serialised), Non-PC(serialised), Non-PC(embedded), Reference
// Join table has : ownerMapping (PK), elementMapping, orderMapping (PK)
elementMapping = storeMgr.getMappingManager().getMapping(this, mmd, clr, FieldRole.ROLE_COLLECTION_ELEMENT);
if (NucleusLogger.DATASTORE.isDebugEnabled()) {
logMapping(mmd.getFullFieldName() + ".[ELEMENT]", elementMapping);
}
} else {
// Element = PC
// Join table has : ownerMapping (PK), elementMapping, orderMapping (optional)
ColumnMetaData[] elemColmd = null;
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
ElementMetaData elemmd = mmd.getElementMetaData();
if (elemmd != null && elemmd.getColumnMetaData() != null && elemmd.getColumnMetaData().length > 0) {
// Column mappings defined at this side (1-N, M-N)
elemColmd = elemmd.getColumnMetaData();
} else if (relatedMmds != null && relatedMmds[0].getJoinMetaData() != null && relatedMmds[0].getJoinMetaData().getColumnMetaData() != null && relatedMmds[0].getJoinMetaData().getColumnMetaData().length > 0) {
// Column mappings defined at other side (M-N) on <join>
elemColmd = relatedMmds[0].getJoinMetaData().getColumnMetaData();
}
elementMapping = ColumnCreator.createColumnsForJoinTables(elementClass, mmd, elemColmd, storeMgr, this, false, false, FieldRole.ROLE_COLLECTION_ELEMENT, clr, null);
RelationType relationType = mmd.getRelationType(clr);
if (Boolean.TRUE.equals(mmd.getContainer().allowNulls()) && relationType != RelationType.MANY_TO_MANY_BI) {
// 1-N : Make all element col(s) nullable so we can store null elements
for (int i = 0; i < elementMapping.getNumberOfDatastoreMappings(); i++) {
Column elementCol = elementMapping.getDatastoreMapping(i).getColumn();
elementCol.setNullable(true);
}
}
if (NucleusLogger.DATASTORE.isDebugEnabled()) {
logMapping(mmd.getFullFieldName() + ".[ELEMENT]", elementMapping);
}
}
PrimaryKeyMetaData pkmd = (mmd.getJoinMetaData() != null ? mmd.getJoinMetaData().getPrimaryKeyMetaData() : null);
boolean pkColsSpecified = (pkmd != null ? pkmd.getColumnMetaData() != null : false);
boolean pkRequired = requiresPrimaryKey();
// Add order mapping if required
boolean orderRequired = false;
if (mmd.getOrderMetaData() != null) {
if (mmd.getOrderMetaData().isIndexedList()) {
// Indexed Collection with <order>, so add index mapping
orderRequired = true;
RelationType relType = mmd.getRelationType(clr);
if (relType == RelationType.MANY_TO_MANY_BI) {
// Don't support M-N using indexed List
throw new NucleusUserException(Localiser.msg("020002", mmd.getFullFieldName())).setFatal();
}
}
} else if (List.class.isAssignableFrom(mmd.getType())) {
// Indexed List with no <order>, so has index mapping
orderRequired = true;
} else if (pkRequired && !pkColsSpecified) {
// PK is required so maybe need to add an index to form the PK
if (isEmbeddedElementPC()) {
if (mmd.getCollection().getElementClassMetaData(clr).getIdentityType() != IdentityType.APPLICATION) {
// Embedded PC with datastore id so we need an index to form the PK
orderRequired = true;
}
} else if (isSerialisedElement()) {
// Serialised element, so need an index to form the PK
orderRequired = true;
} else if (elementMapping instanceof ReferenceMapping) {
// ReferenceMapping, so have order if more than 1 implementation
ReferenceMapping refMapping = (ReferenceMapping) elementMapping;
if (refMapping.getJavaTypeMapping().length > 1) {
orderRequired = true;
}
} else if (!(elementMapping instanceof PersistableMapping)) {
// Non-PC, so depends if the element column can be used as part of a PK
// TODO This assumes the elementMapping has a single column but what if it is Color with 4 cols?
Column elementCol = elementMapping.getDatastoreMapping(0).getColumn();
if (!storeMgr.getDatastoreAdapter().isValidPrimaryKeyType(elementCol.getJdbcType())) {
// Not possible to use this Non-PC type as part of the PK
orderRequired = true;
}
}
}
if (orderRequired) {
// Order (index) column is required (integer based)
ColumnMetaData orderColmd = null;
if (mmd.getOrderMetaData() != null && mmd.getOrderMetaData().getColumnMetaData() != null && mmd.getOrderMetaData().getColumnMetaData().length > 0) {
// Specified "order" column info
orderColmd = mmd.getOrderMetaData().getColumnMetaData()[0];
if (orderColmd.getName() == null) {
// No column name so use default
orderColmd = new ColumnMetaData(orderColmd);
DatastoreIdentifier id = storeMgr.getIdentifierFactory().newIndexFieldIdentifier(mmd);
orderColmd.setName(id.getName());
}
} else {
// No column name so use default
DatastoreIdentifier id = storeMgr.getIdentifierFactory().newIndexFieldIdentifier(mmd);
orderColmd = new ColumnMetaData();
orderColmd.setName(id.getName());
}
// JDO2 spec [18.5] order column is assumed to be "int"
orderMapping = storeMgr.getMappingManager().getMapping(int.class);
ColumnCreator.createIndexColumn(orderMapping, storeMgr, clr, this, orderColmd, pkRequired && !pkColsSpecified);
if (NucleusLogger.DATASTORE.isDebugEnabled()) {
logMapping(mmd.getFullFieldName() + ".[ORDER]", orderMapping);
}
}
// Define primary key of the join table (if any)
if (pkRequired) {
if (pkColsSpecified) {
// Apply the users PK specification
applyUserPrimaryKeySpecification(pkmd);
} else {
// Define PK
for (int i = 0; i < ownerMapping.getNumberOfDatastoreMappings(); i++) {
ownerMapping.getDatastoreMapping(i).getColumn().setPrimaryKey();
}
if (orderRequired) {
// Order column specified so owner+order are the PK
orderMapping.getDatastoreMapping(0).getColumn().setPrimaryKey();
} else {
// No order column specified so owner+element are the PK
for (int i = 0; i < elementMapping.getNumberOfDatastoreMappings(); i++) {
elementMapping.getDatastoreMapping(i).getColumn().setPrimaryKey();
}
}
}
}
if (NucleusLogger.DATASTORE_SCHEMA.isDebugEnabled()) {
NucleusLogger.DATASTORE_SCHEMA.debug(Localiser.msg("057023", this));
}
storeMgr.registerTableInitialized(this);
state = TABLE_STATE_INITIALIZED;
}
use of org.datanucleus.metadata.RelationType in project datanucleus-rdbms by datanucleus.
the class ClassTable method manageMembers.
/**
* Goes through all specified members for the specified class and adds a mapping for each.
* Ignores primary-key fields which are added elsewhere.
* @param theCmd ClassMetaData for the class to be managed
* @param clr The ClassLoaderResolver
* @param mmds the fields/properties to manage
*/
private void manageMembers(AbstractClassMetaData theCmd, ClassLoaderResolver clr, AbstractMemberMetaData[] mmds) {
// Go through the fields for this class and add columns for them
for (int fieldNumber = 0; fieldNumber < mmds.length; fieldNumber++) {
// Primary key fields are added by the initialisePK method
AbstractMemberMetaData mmd = mmds[fieldNumber];
if (!mmd.isPrimaryKey()) {
if (managesMember(mmd.getFullFieldName())) {
if (!mmd.getClassName(true).equals(theCmd.getFullClassName())) {
// Field already managed by this table so maybe we are overriding a superclass
JavaTypeMapping fieldMapping = getMappingForMemberName(mmd.getFullFieldName());
ColumnMetaData[] colmds = mmd.getColumnMetaData();
if (colmds != null && colmds.length > 0) {
// Apply this set of ColumnMetaData to the existing mapping
int colnum = 0;
IdentifierFactory idFactory = getStoreManager().getIdentifierFactory();
for (int i = 0; i < fieldMapping.getNumberOfDatastoreMappings(); i++) {
Column col = fieldMapping.getDatastoreMapping(i).getColumn();
col.setIdentifier(idFactory.newColumnIdentifier(colmds[colnum].getName()));
col.setColumnMetaData(colmds[colnum]);
colnum++;
if (colnum == colmds.length) {
// Reached end of specified metadata
break;
}
}
// TODO Change this to reflect that we have updated the previous mapping
logMapping(mmd.getFullFieldName(), fieldMapping);
}
}
} else {
// Manage the field if not already managed (may already exist if overriding a superclass field)
if (mmd.getPersistenceModifier() == FieldPersistenceModifier.PERSISTENT) {
boolean isPrimary = true;
if (mmd.getTable() != null && mmd.getJoinMetaData() == null) {
// Field has a table specified and is not a 1-N with join table
// so is mapped to a secondary table
isPrimary = false;
}
if (isPrimary) {
// Add the field to this table
JavaTypeMapping fieldMapping = storeMgr.getMappingManager().getMapping(this, mmd, clr, FieldRole.ROLE_FIELD);
if (theCmd != cmd && theCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUPERCLASS_TABLE && fieldMapping.getNumberOfDatastoreMappings() > 0) {
// Field is for a subclass and so column(s) has to either allow nulls, or have default
int numCols = fieldMapping.getNumberOfDatastoreMappings();
for (int colNum = 0; colNum < numCols; colNum++) {
Column col = fieldMapping.getDatastoreMapping(colNum).getColumn();
if (col.getDefaultValue() == null && !col.isNullable()) {
// Column needs to be nullable
NucleusLogger.DATASTORE_SCHEMA.debug("Member " + mmd.getFullFieldName() + " uses superclass-table yet the field is not marked as nullable " + " nor does it have a default value, so setting the column as nullable");
col.setNullable(true);
}
}
}
addMemberMapping(fieldMapping);
} else {
// Add the field to the appropriate secondary table
if (secondaryTables == null) {
secondaryTables = new HashMap();
}
SecondaryTable secTable = secondaryTables.get(mmd.getTable());
if (secTable == null) {
// Secondary table doesnt exist yet so create it to users specifications.
List<JoinMetaData> joinmds = theCmd.getJoinMetaData();
JoinMetaData theJoinMD = null;
if (joinmds != null) {
for (JoinMetaData joinmd : joinmds) {
if (joinmd.getTable().equalsIgnoreCase(mmd.getTable()) && (joinmd.getCatalog() == null || (joinmd.getCatalog() != null && joinmd.getCatalog().equalsIgnoreCase(mmd.getCatalog()))) && (joinmd.getSchema() == null || (joinmd.getSchema() != null && joinmd.getSchema().equalsIgnoreCase(mmd.getSchema())))) {
theJoinMD = joinmd;
break;
}
}
}
DatastoreIdentifier secTableIdentifier = storeMgr.getIdentifierFactory().newTableIdentifier(mmd.getTable());
// Use specified catalog, else take catalog of the owning table
String catalogName = mmd.getCatalog();
if (catalogName == null) {
catalogName = getCatalogName();
}
// Use specified schema, else take schema of the owning table
String schemaName = mmd.getSchema();
if (schemaName == null) {
schemaName = getSchemaName();
}
secTableIdentifier.setCatalogName(catalogName);
secTableIdentifier.setSchemaName(schemaName);
secTable = new SecondaryTable(secTableIdentifier, storeMgr, this, theJoinMD, clr);
secTable.preInitialize(clr);
secTable.initialize(clr);
secTable.postInitialize(clr);
secondaryTables.put(mmd.getTable(), secTable);
}
secTable.addMemberMapping(storeMgr.getMappingManager().getMapping(secTable, mmd, clr, FieldRole.ROLE_FIELD));
}
} else if (mmd.getPersistenceModifier() != FieldPersistenceModifier.TRANSACTIONAL) {
throw new NucleusException(Localiser.msg("057006", mmd.getName())).setFatal();
}
// Calculate if we need a FK adding due to a 1-N (FK) relationship
boolean needsFKToContainerOwner = false;
RelationType relationType = mmd.getRelationType(clr);
if (relationType == RelationType.ONE_TO_MANY_BI) {
AbstractMemberMetaData[] relatedMmds = mmd.getRelatedMemberMetaData(clr);
if (mmd.getJoinMetaData() == null && relatedMmds[0].getJoinMetaData() == null) {
needsFKToContainerOwner = true;
}
} else if (relationType == RelationType.ONE_TO_MANY_UNI && !mmd.isSingleCollection()) {
if (mmd.getJoinMetaData() == null) {
needsFKToContainerOwner = true;
}
}
if (needsFKToContainerOwner) {
// 1-N uni/bidirectional using FK, so update the element side with a FK
if ((mmd.getCollection() != null && !SCOUtils.collectionHasSerialisedElements(mmd)) || (mmd.getArray() != null && !SCOUtils.arrayIsStoredInSingleColumn(mmd, storeMgr.getMetaDataManager()))) {
// 1-N ForeignKey collection/array, so add FK to element table
AbstractClassMetaData elementCmd = null;
if (mmd.hasCollection()) {
// Collection
elementCmd = storeMgr.getMetaDataManager().getMetaDataForClass(mmd.getCollection().getElementType(), clr);
} else {
// Array
elementCmd = storeMgr.getMetaDataManager().getMetaDataForClass(mmd.getType().getComponentType(), clr);
}
if (elementCmd == null) {
String[] implClassNames = storeMgr.getMetaDataManager().getClassesImplementingInterface(mmd.getCollection().getElementType(), clr);
if (implClassNames != null && implClassNames.length > 0) {
// Collection/array of interface type so apply callback to all implementation types
AbstractClassMetaData[] elementCmds = new AbstractClassMetaData[implClassNames.length];
for (int i = 0; i < implClassNames.length; i++) {
elementCmds[i] = storeMgr.getMetaDataManager().getMetaDataForClass(implClassNames[i], clr);
}
// Run callbacks for each of the element classes.
for (int i = 0; i < elementCmds.length; i++) {
storeMgr.addSchemaCallback(elementCmds[i].getFullClassName(), mmd);
DatastoreClass dc = storeMgr.getDatastoreClass(elementCmds[i].getFullClassName(), clr);
if (dc == null) {
throw new NucleusException("Unable to add foreign-key to " + elementCmds[i].getFullClassName() + " to " + this + " since element has no table!");
}
if (dc instanceof ClassTable) {
ClassTable ct = (ClassTable) dc;
if (ct.isInitialized()) {
// if the target table is already initialized, run the callbacks
ct.runCallBacks(clr);
}
} else {
NucleusLogger.DATASTORE_SCHEMA.info("Table " + toString() + " has to manage member " + mmd.getFullFieldName() + " yet the related element uses a VIEW so not remotely adding element FK owner column; assumed to be part of the VIEW definition");
}
}
} else {
// Elements that are reference types or non-PC will come through here
if (mmd.hasCollection()) {
NucleusLogger.METADATA.warn(Localiser.msg("057016", theCmd.getFullClassName(), mmd.getCollection().getElementType()));
} else {
NucleusLogger.METADATA.warn(Localiser.msg("057014", theCmd.getFullClassName(), mmd.getType().getComponentType().getName()));
}
}
} else {
AbstractClassMetaData[] elementCmds = null;
// TODO : Cater for interface elements, and get the metadata for the implementation classes here
if (elementCmd.getBaseAbstractClassMetaData().getInheritanceMetaData().getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
// COMPLETE-TABLE inheritance in element, so really need FK in each!
Collection<String> elementSubclassNames = storeMgr.getSubClassesForClass(elementCmd.getFullClassName(), true, clr);
elementCmds = new ClassMetaData[elementSubclassNames != null ? 1 + elementSubclassNames.size() : 1];
int elemNo = 0;
elementCmds[elemNo++] = elementCmd;
if (elementSubclassNames != null) {
for (String elementSubclassName : elementSubclassNames) {
AbstractClassMetaData elemSubCmd = storeMgr.getMetaDataManager().getMetaDataForClass(elementSubclassName, clr);
elementCmds[elemNo++] = elemSubCmd;
}
}
} else if (elementCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE) {
elementCmds = storeMgr.getClassesManagingTableForClass(elementCmd, clr);
} else {
elementCmds = new ClassMetaData[1];
elementCmds[0] = elementCmd;
}
ElementMetaData elemmd = mmd.getElementMetaData();
if (elemmd != null && !StringUtils.isWhitespace(elemmd.getTable())) {
DatastoreIdentifier requiredTableId = storeMgr.getIdentifierFactory().newTableIdentifier(elemmd.getTable());
DatastoreClass requiredTable = storeMgr.getDatastoreClass(requiredTableId);
if (requiredTable != null) {
// TODO Respect specification of table in ElementMetaData rather than just defaulting to table of element type
// Note that this will need updates to FKListStore, FKSetStore etc to look for the table
NucleusLogger.GENERAL.warn("Member=" + mmd.getFullFieldName() + " has 1-N FK with required table=" + requiredTable + " : we don't currently support specification of the element table, and always take the default table for the element type");
/*for (int i=0;i<elementCmds.length;i++)
{
AbstractClassMetaData theElementCmd = elementCmds[i];
while (theElementCmd != null)
{
if (requiredTable.managesClass(theElementCmd.getFullClassName()))
{
if (theElementCmd != elementCmds[i])
{
elementCmds = new ClassMetaData[1];
elementCmds[0] = theElementCmd;
break;
}
}
theElementCmd = theElementCmd.getSuperAbstractClassMetaData();
}
}*/
} else {
NucleusLogger.DATASTORE_SCHEMA.warn("Member " + mmd.getFullFieldName() + " specified element FK in table=" + elemmd.getTable() + " but table not known. Ignoring.");
}
}
// Run callbacks for each of the element classes
for (int i = 0; i < elementCmds.length; i++) {
storeMgr.addSchemaCallback(elementCmds[i].getFullClassName(), mmd);
DatastoreClass dc = storeMgr.getDatastoreClass(elementCmds[i].getFullClassName(), clr);
if (// If dc is null then we assume the (possible) element is abstract so no FK needed
dc != null) {
if (dc instanceof ClassTable) {
ClassTable ct = (ClassTable) dc;
if (ct.isInitialized()) {
// if the target table is already initialized, run the callbacks
ct.runCallBacks(clr);
}
} else {
NucleusLogger.DATASTORE_SCHEMA.info("Table " + toString() + " has to manage member " + mmd.getFullFieldName() + " yet the related element uses a VIEW so not remotely adding element FK owner column; assumed to be part of the VIEW definition");
}
}
}
}
} else if (mmd.getMap() != null && !SCOUtils.mapHasSerialisedKeysAndValues(mmd)) {
// 1-N ForeignKey map, so add FK to value table
if (mmd.getKeyMetaData() != null && mmd.getKeyMetaData().getMappedBy() != null) {
// Key is stored in the value table so add the FK to the value table
AbstractClassMetaData valueCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(mmd.getMap().getValueType(), clr);
if (valueCmd == null) {
// Interface elements will come through here and java.lang.String and others as well
NucleusLogger.METADATA.warn(Localiser.msg("057018", theCmd.getFullClassName(), mmd.getMap().getValueType()));
} else {
AbstractClassMetaData[] valueCmds = null;
// TODO : Cater for interface values, and get the metadata for the implementation classes here
if (valueCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE) {
valueCmds = storeMgr.getClassesManagingTableForClass(valueCmd, clr);
} else {
valueCmds = new ClassMetaData[1];
valueCmds[0] = valueCmd;
}
// Run callbacks for each of the value classes.
for (int i = 0; i < valueCmds.length; i++) {
storeMgr.addSchemaCallback(valueCmds[i].getFullClassName(), mmd);
DatastoreClass dc = storeMgr.getDatastoreClass(valueCmds[i].getFullClassName(), clr);
if (dc instanceof ClassTable) {
ClassTable ct = (ClassTable) dc;
if (ct.isInitialized()) {
// if the target table is already initialized, run the callbacks
ct.runCallBacks(clr);
}
} else {
NucleusLogger.DATASTORE_SCHEMA.info("Table " + toString() + " has to manage member " + mmd.getFullFieldName() + " yet the related value uses a VIEW so not remotely adding value owner FK column; assumed to be part of the VIEW definition");
}
}
}
} else if (mmd.getValueMetaData() != null && mmd.getValueMetaData().getMappedBy() != null) {
// Value is stored in the key table so add the FK to the key table
AbstractClassMetaData keyCmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(mmd.getMap().getKeyType(), clr);
if (keyCmd == null) {
// Interface elements will come through here and java.lang.String and others as well
NucleusLogger.METADATA.warn(Localiser.msg("057019", theCmd.getFullClassName(), mmd.getMap().getKeyType()));
} else {
AbstractClassMetaData[] keyCmds = null;
// TODO : Cater for interface keys, and get the metadata for the implementation classes here
if (keyCmd.getInheritanceMetaData().getStrategy() == InheritanceStrategy.SUBCLASS_TABLE) {
keyCmds = storeMgr.getClassesManagingTableForClass(keyCmd, clr);
} else {
keyCmds = new ClassMetaData[1];
keyCmds[0] = keyCmd;
}
// Run callbacks for each of the key classes.
for (int i = 0; i < keyCmds.length; i++) {
storeMgr.addSchemaCallback(keyCmds[i].getFullClassName(), mmd);
DatastoreClass dc = storeMgr.getDatastoreClass(keyCmds[i].getFullClassName(), clr);
if (dc instanceof ClassTable) {
ClassTable ct = (ClassTable) dc;
if (ct.isInitialized()) {
// if the target table is already initialized, run the callbacks
ct.runCallBacks(clr);
}
} else {
NucleusLogger.DATASTORE_SCHEMA.info("Table " + toString() + " has to manage member " + mmd.getFullFieldName() + " yet the related key uses a VIEW so not remotely adding key FK owner column; assumed to be part of the VIEW definition");
}
}
}
}
}
}
}
}
}
}
use of org.datanucleus.metadata.RelationType in project datanucleus-rdbms by datanucleus.
the class RDBMSPersistenceHandler method fetchObject.
// ------------------------------ Fetch ----------------------------------
/**
* Fetches (fields of) a persistent object from the database.
* This does a single SELECT on the candidate of the class in question. Will join to inherited
* tables as appropriate to get values persisted into other tables. Can also join to the tables of
* related objects (1-1, N-1) as neccessary to retrieve those objects.
* @param op Object Provider of the object to be fetched.
* @param memberNumbers The numbers of the members to be fetched.
* @throws NucleusObjectNotFoundException if the object doesn't exist
* @throws NucleusDataStoreException when an error occurs in the datastore communication
*/
public void fetchObject(ObjectProvider op, int[] memberNumbers) {
ExecutionContext ec = op.getExecutionContext();
ClassLoaderResolver clr = ec.getClassLoaderResolver();
// Extract metadata of members to process
AbstractMemberMetaData[] mmds = null;
if (memberNumbers != null && memberNumbers.length > 0) {
int[] memberNumbersToProcess = memberNumbers;
AbstractClassMetaData cmd = op.getClassMetaData();
if (storeMgr.getBooleanProperty(RDBMSPropertyNames.PROPERTY_RDBMS_FETCH_UNLOADED_AUTO)) {
// Here we simply load up any unloaded non-relation or 1-1/N-1 members
if (!op.getLifecycleState().isDeleted()) {
// Check if this will actually do a SELECT (because we don't want to impose that if not otherwise)
boolean fetchPerformsSelect = false;
for (int i = 0; i < memberNumbers.length; i++) {
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(memberNumbers[i]);
RelationType relationType = mmd.getRelationType(clr);
if (relationType != RelationType.ONE_TO_MANY_UNI && relationType != RelationType.ONE_TO_MANY_BI && relationType != RelationType.MANY_TO_MANY_BI) {
fetchPerformsSelect = true;
break;
}
}
if (fetchPerformsSelect) {
// Definitely does a SELECT, so try to identify any additional non-relation or 1-1, N-1
// members that aren't loaded that could be fetched right now in this call.
List<Integer> memberNumberList = new ArrayList<>();
for (int i = 0; i < memberNumbers.length; i++) {
memberNumberList.add(memberNumbers[i]);
}
// Check if we could retrieve any other unloaded fields in this call
boolean[] loadedFlags = op.getLoadedFields();
for (int i = 0; i < loadedFlags.length; i++) {
boolean requested = false;
for (int j = 0; j < memberNumbers.length; j++) {
if (memberNumbers[j] == i) {
requested = true;
break;
}
}
if (!requested && !loadedFlags[i]) {
AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(i);
RelationType relType = mmd.getRelationType(clr);
if (relType == RelationType.NONE || relType == RelationType.ONE_TO_ONE_BI || relType == RelationType.ONE_TO_ONE_UNI) {
memberNumberList.add(i);
}
}
}
memberNumbersToProcess = new int[memberNumberList.size()];
int i = 0;
Iterator<Integer> fieldNumberIter = memberNumberList.iterator();
while (fieldNumberIter.hasNext()) {
memberNumbersToProcess[i++] = fieldNumberIter.next();
}
}
}
}
// Convert the field numbers for this class into their metadata for the class
mmds = new AbstractMemberMetaData[memberNumbersToProcess.length];
for (int i = 0; i < mmds.length; i++) {
mmds[i] = cmd.getMetaDataForManagedMemberAtAbsolutePosition(memberNumbersToProcess[i]);
}
}
if (op.isEmbedded()) {
StringBuilder str = new StringBuilder();
if (mmds != null) {
for (int i = 0; i < mmds.length; i++) {
if (i > 0) {
str.append(',');
}
str.append(mmds[i].getName());
}
}
NucleusLogger.PERSISTENCE.info("Request to load fields \"" + str.toString() + "\" of class " + op.getClassMetaData().getFullClassName() + " but object is embedded, so ignored");
} else {
if (ec.getStatistics() != null) {
ec.getStatistics().incrementFetchCount();
}
DatastoreClass table = getDatastoreClass(op.getClassMetaData().getFullClassName(), clr);
Request req = getFetchRequest(table, mmds, op.getClassMetaData(), clr);
req.execute(op);
}
}
Aggregations