All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.descriptors.TablePerClassPolicy Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*******************************************************************************
 * Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved.
 * This program and the accompanying materials are made available under the 
 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 
 * which accompanies this distribution. 
 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at 
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * Contributors:
 *     12/12/2008-1.1 Guy Pelletier 
 *       - 249860: Implement table per class inheritance support.
 ******************************************************************************/  
package org.eclipse.persistence.descriptors;

import java.io.*;
import java.util.*;

import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.internal.helper.DatabaseField;
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.ForeignReferenceMapping;
import org.eclipse.persistence.mappings.ManyToManyMapping;
import org.eclipse.persistence.mappings.OneToManyMapping;
import org.eclipse.persistence.mappings.OneToOneMapping;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.eclipse.persistence.queries.ReadObjectQuery;

/**
 * 

Purpose: Provides the functionality to support a TABLE_PER_CLASS * inheritance strategy. Resolves relational mappings and querying. */ public class TablePerClassPolicy extends InterfacePolicy implements Serializable, Cloneable { /** * Selection queries from read all mappings will be cached and re-used. * E.G Entity A has a 1-M to Entity D (who has a subclass Entity E). We will * build a selection query to Entity E based on the selection query from the * 1-M mapping from Entity A to Entity D. */ protected HashMap selectionQueriesForAllObjects; /** * INTERNAL: * Create a new policy. * Only descriptors involved in inheritance should have a policy. */ public TablePerClassPolicy(ClassDescriptor descriptor) { setDescriptor(descriptor); selectionQueriesForAllObjects = new HashMap(); } /** * INTERNAL: */ protected void addSelectionQuery(ForeignReferenceMapping cloneMapping, ForeignReferenceMapping sourceMapping, AbstractSession session) { // Set the new reference class cloneMapping.setReferenceClass(getDescriptor().getJavaClass()); cloneMapping.setReferenceClassName(getDescriptor().getJavaClassName()); // Force the selection criteria to be re-built. cloneMapping.setForceInitializationOfSelectionCriteria(true); // Now initialize the mapping cloneMapping.initialize(session); // The selection query should be initialized with all the right // goodies now, cache it for quick retrieval. ObjectLevelReadQuery selectionQuery = (ObjectLevelReadQuery) cloneMapping.getSelectionQuery(); selectionQuery.getExpressionBuilder().setQueryClassAndDescriptor(descriptor.getJavaClass(), descriptor); // By default its source mapping will be the cloned mapping, we // need to set the actual source mapping so that we can look it // back up correctly. selectionQuery.setSourceMapping(sourceMapping); // Cache the selection query for this source mapping. selectionQueriesForAllObjects.put(sourceMapping, selectionQuery); } /** * INTERNAL: */ public boolean isTablePerClassPolicy() { return true; } /** * INTERNAL: * This method is called from individual mappings during their * initialization. If the mapping is to a class within a TABLE_PER_CLASS * inheritance hierarchy, what this method will do is prepare a selection * query to execute for every child descriptor in the hierarchy. * * The selection queries are created by cloning the source mapping, * updating the necessary database fields on the mapping and then * initializing the mapping to create the internal selection query. * This query is then cached where needed using the source mapping's * selection query name as the key. * * @see selectAllObjects(ReadAllQuery) * @see selectOneObject(ReadObjectQuery) */ public void prepareChildrenSelectionQuery(DatabaseMapping sourceMapping, AbstractSession session) { // From collection mappings we must execute a query on every // subclass table to build our results. Tell all children // descriptors to prepare their selection queries. for (ClassDescriptor childDescriptor : (Vector) getChildDescriptors()) { childDescriptor.getTablePerClassPolicy().prepareSelectionQuery(sourceMapping, session); } } /** * INTERNAL: */ protected void prepareManyToManySelectionQuery(ManyToManyMapping sourceMapping, AbstractSession session) { // Clone the mapping because in reality that is what we have, that // is, a M-M mapping to each class of the hierarchy. ManyToManyMapping manyToMany = (ManyToManyMapping) sourceMapping.clone(); // Update the foreign key fields on the mapping. Basically, take the // table name off and let the descriptor figure it out. for (DatabaseField keyField : manyToMany.getTargetKeyFields()) { keyField.setTable(new DatabaseTable()); } addSelectionQuery(manyToMany, sourceMapping, session); } /** * INTERNAL: */ protected void prepareOneToManySelectionQuery(OneToManyMapping sourceMapping, AbstractSession session) { // Clone the mapping because in reality that is what we have, that // is, a 1-M mapping to each class of the hierarchy. OneToManyMapping oneToMany = (OneToManyMapping) sourceMapping.clone(); // Update the foreign key fields on the mapping. Basically, take the // table name off and let the descriptor figure it out. Vector targetForeignKeyFields = new Vector(); for (DatabaseField fkField : oneToMany.getTargetForeignKeysToSourceKeys().keySet()) { targetForeignKeyFields.add(new DatabaseField(fkField.getName())); } // Update our foreign key fields and clear the key maps. oneToMany.setTargetForeignKeyFields(targetForeignKeyFields); oneToMany.getTargetForeignKeysToSourceKeys().clear(); oneToMany.getSourceKeysToTargetForeignKeys().clear(); addSelectionQuery(oneToMany, sourceMapping, session); } /** * INTERNAL: */ protected void prepareOneToOneSelectionQuery(OneToOneMapping sourceMapping, AbstractSession session) { // Clone the mapping because in reality that is what we have, that // is, a 1-1 mapping to each class of the hierarchy. OneToOneMapping oneToOne = (OneToOneMapping) sourceMapping.clone(); // Update the target keys to have an empty table (descriptor will figure it out) for (DatabaseField targetField : oneToOne.getTargetToSourceKeyFields().keySet()) { targetField.setTable(new DatabaseTable()); } addSelectionQuery(oneToOne, sourceMapping, session); } /** * INTERNAL: * The selection queries are created by cloning the source mapping, * updating the necessary database fields on the mapping and then * initializing the mapping to create the internal selection query. * This query is then cached where needed using the source mapping * as the key. A prepare is performed for each child of the hierarchy. */ protected void prepareSelectionQuery(DatabaseMapping sourceMapping, AbstractSession session) { // Recurse through our child descriptors to set up the selection query // before execution. for (ClassDescriptor childDescriptor : (Vector) getChildDescriptors()) { childDescriptor.getTablePerClassPolicy().prepareSelectionQuery(sourceMapping, session); } if (sourceMapping.isOneToManyMapping()) { prepareOneToManySelectionQuery((OneToManyMapping) sourceMapping, session); } else if (sourceMapping.isManyToManyMapping()) { prepareManyToManySelectionQuery((ManyToManyMapping) sourceMapping, session); } else if (sourceMapping.isOneToOneMapping()) { prepareOneToOneSelectionQuery((OneToOneMapping) sourceMapping, session); } // No support for other mappings at this point. } /** * INTERNAL: * Select all objects for a concrete descriptor. */ @Override protected Object selectAllObjects(ReadAllQuery query) { if (this.descriptor.isAbstract()) { return query.getContainerPolicy().containerInstance(); } // If we came from a source mapping the execute the selection query // we prepared from it. if (selectionQueriesForAllObjects.containsKey(query.getSourceMapping())) { return query.getExecutionSession().executeQuery(selectionQueriesForAllObjects.get(query.getSourceMapping()), query.getTranslationRow()); } else { return super.selectAllObjects(query); } } /** * INTERNAL: * Select one object of any concrete subclass. */ @Override protected Object selectOneObject(ReadObjectQuery query) throws DescriptorException { if (this.descriptor.isAbstract()) { return null; } // If we came from a source mapping the execute the selection query // we prepared from it. if (selectionQueriesForAllObjects.containsKey(query.getSourceMapping())) { return query.getExecutionSession().executeQuery(selectionQueriesForAllObjects.get(query.getSourceMapping()), query.getTranslationRow()); } else { // Assuming we're doing a find by primary key ... // We have to update the translation row to be to the correct field. AbstractRecord translationRow = query.getTranslationRow().clone(); Vector allFields = new Vector(); for (DatabaseField field : translationRow.getFields()) { // Remove the table and let the descriptor figure it out. allFields.add(new DatabaseField(field.getName())); } translationRow.getFields().clear(); translationRow.getFields().addAll(allFields); return query.getSession().executeQuery(getDescriptor().getQueryManager().getReadObjectQuery(), translationRow); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy