db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From arm...@apache.org
Subject cvs commit: db-ojb release-notes.txt
Date Tue, 21 Sep 2004 00:29:02 GMT
arminw      2004/09/20 17:29:02

  Modified:    src/java/org/apache/ojb/broker/core Tag: OJB_1_0_RELEASE
                        MtoNBroker.java PersistenceBrokerImpl.java
               src/test/org/apache/ojb/broker Tag: OJB_1_0_RELEASE
                        M2NTest.java
               .        Tag: OJB_1_0_RELEASE release-notes.txt
  Log:
  improve m:n performance, adapted version from trunk
  fix m:n insert problem when using "linking"
  
  Revision  Changes    Path
  No                   revision
  No                   revision
  1.10.2.1  +230 -59   db-ojb/src/java/org/apache/ojb/broker/core/MtoNBroker.java
  
  Index: MtoNBroker.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/MtoNBroker.java,v
  retrieving revision 1.10
  retrieving revision 1.10.2.1
  diff -u -r1.10 -r1.10.2.1
  --- MtoNBroker.java	9 Apr 2004 13:22:28 -0000	1.10
  +++ MtoNBroker.java	21 Sep 2004 00:29:01 -0000	1.10.2.1
  @@ -15,6 +15,7 @@
    * limitations under the License.
    */
   
  +import java.io.Serializable;
   import java.util.ArrayList;
   import java.util.Collection;
   import java.util.Iterator;
  @@ -23,8 +24,9 @@
   
   import org.apache.commons.lang.builder.EqualsBuilder;
   import org.apache.commons.lang.builder.HashCodeBuilder;
  +import org.apache.commons.lang.builder.ToStringBuilder;
   import org.apache.ojb.broker.MtoNImplementor;
  -import org.apache.ojb.broker.PersistenceBroker;
  +import org.apache.ojb.broker.OJBRuntimeException;
   import org.apache.ojb.broker.PersistenceBrokerException;
   import org.apache.ojb.broker.accesslayer.ResultSetAndStatement;
   import org.apache.ojb.broker.core.proxy.ProxyHelper;
  @@ -51,54 +53,78 @@
   {
       private Logger log = LoggerFactory.getLogger(MtoNBroker.class);
   
  -    private PersistenceBroker pb;
  +    private PersistenceBrokerImpl pb;
  +    /**
  +     * Used to store {@link GenericObject} while transaction running, used as
  +     * workaround for m:n insert problem.
  +     * TODO: find better solution for m:n handling
  +     */
  +    private List tempObjects = new ArrayList();
   
  -    public MtoNBroker(final PersistenceBroker broker)
  +    public MtoNBroker(final PersistenceBrokerImpl broker)
       {
           this.pb = broker;
       }
   
  +    public void reset()
  +    {
  +        tempObjects.clear();
  +    }
  +
       /**
        * Stores new values of a M:N association in a indirection table.
  +     *
  +     * @param cod        The {@link org.apache.ojb.broker.metadata.CollectionDescriptor}
for the m:n relation
  +     * @param realObject The real object
  +     * @param otherObj   The referenced object
  +     * @param mnKeys     The all {@link org.apache.ojb.broker.core.MtoNBroker.Key} matching
the real object
        */
  -    public void storeMtoNImplementor(CollectionDescriptor cod, Object obj, Object otherObj,
Collection mnKeys)
  +    public void storeMtoNImplementor(CollectionDescriptor cod, Object realObject, Object
otherObj, Collection mnKeys)
       {
  -        ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(obj.getClass());
  -        ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, obj);
  +        ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(realObject.getClass());
  +        ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, realObject);
           String[] pkColumns = cod.getFksToThisClass();
   
  -        otherObj = ProxyHelper.getRealObject(otherObj);
  -        ClassDescriptor otherCld = pb.getDescriptorRepository().getDescriptorFor(otherObj.getClass());
  +        ClassDescriptor otherCld = pb.getDescriptorRepository().getDescriptorFor(ProxyHelper.getRealClass(otherObj));
           ValueContainer[] otherPkValues = pb.serviceBrokerHelper().getKeyValues(otherCld,
otherObj);
   
           String[] otherPkColumns = cod.getFksToItemClass();
           String table = cod.getIndirectionTable();
           MtoNBroker.Key key = new MtoNBroker.Key(otherPkValues);
   
  -        if (mnKeys.contains(key))
  +        if(mnKeys.contains(key))
           {
               return;
           }
   
  +        String[] cols = mergeColumns(pkColumns, otherPkColumns);
           String insertStmt = pb.serviceSqlGenerator().getInsertMNStatement(table, pkColumns,
otherPkColumns);
  -        pb.serviceJdbcAccess().executeUpdateSQL(insertStmt, cld, pkValues, otherPkValues);
  +        ValueContainer[] values = mergeContainer(pkValues, otherPkValues);
  +        GenericObject gObj = new GenericObject(table, cols, values);
  +        if(! tempObjects.contains(gObj))
  +        {
  +            pb.serviceJdbcAccess().executeUpdateSQL(insertStmt, cld, pkValues, otherPkValues);
  +            tempObjects.add(gObj);
  +        }
       }
   
       /**
        * get a Collection of Keys of already existing m:n rows
  +     *
        * @param cod
        * @param obj
        * @return Collection of Key
        */
  -    public Collection getMtoNImplementor(CollectionDescriptor cod, Object obj)
  +    public List getMtoNImplementor(CollectionDescriptor cod, Object obj)
       {
           ResultSetAndStatement rs = null;
  -        List result = new ArrayList();
  +        ArrayList result = new ArrayList();
           ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(obj.getClass());
           ValueContainer[] pkValues = pb.serviceBrokerHelper().getKeyValues(cld, obj);
           String[] pkColumns = cod.getFksToThisClass();
           String[] fkColumns = cod.getFksToItemClass();
           String table = cod.getIndirectionTable();
  +
           String selectStmt = pb.serviceSqlGenerator().getSelectMNStatement(table, fkColumns,
pkColumns);
   
           ClassDescriptor itemCLD = pb.getDescriptorRepository().getDescriptorFor(cod.getItemClass());
  @@ -112,24 +138,24 @@
           {
               throw new PersistenceBrokerException("All pk fields of the element-class need
to" +
                       " be declared in the indirection table. Element class is "
  -                    + itemCLD.getClassNameOfObject() + " with "+itemClassPKFields.length
+ " pk-fields." +
  +                    + itemCLD.getClassNameOfObject() + " with " + itemClassPKFields.length
+ " pk-fields." +
                       " Declared 'fk-pointing-to-element-class' elements in collection-descriptor
are"
                       + fkColumns.length);
           }
           try
           {
               rs = pb.serviceJdbcAccess().executeSQL(selectStmt, cld, pkValues, Query.NOT_SCROLLABLE);
  -            while (rs.m_rs.next())
  +            while(rs.m_rs.next())
               {
                   ValueContainer[] row = new ValueContainer[fkColumns.length];
  -                for (int i = 0; i < row.length; i++)
  +                for(int i = 0; i < row.length; i++)
                   {
                       row[i] = new ValueContainer(rs.m_rs.getObject(i + 1), itemClassPKFields[i].getJdbcType());
                   }
                   result.add(new MtoNBroker.Key(row));
               }
           }
  -        catch (Exception e)
  +        catch(Exception e)
           {
               throw new PersistenceBrokerException(e);
           }
  @@ -141,10 +167,11 @@
       }
   
       /**
  -    * delete all rows from m:n table belonging to obj
  -    * @param cod
  -    * @param obj
  -    */
  +     * delete all rows from m:n table belonging to obj
  +     *
  +     * @param cod
  +     * @param obj
  +     */
       public void deleteMtoNImplementor(CollectionDescriptor cod, Object obj)
       {
           ClassDescriptor cld = pb.getDescriptorRepository().getDescriptorFor(obj.getClass());
  @@ -157,6 +184,7 @@
   
       /**
        * deletes all rows from m:n table that are not used in relatedObjects
  +     *
        * @param cod
        * @param obj
        * @param collectionIterator
  @@ -164,7 +192,7 @@
        */
       public void deleteMtoNImplementor(CollectionDescriptor cod, Object obj, Iterator collectionIterator,
Collection mnKeys)
       {
  -        if (mnKeys.isEmpty() || collectionIterator == null)
  +        if(mnKeys.isEmpty() || collectionIterator == null)
           {
               return;
           }
  @@ -174,7 +202,7 @@
           Object relatedObj;
   
           // remove keys of relatedObject from the existing m:n rows in workList
  -        while (collectionIterator.hasNext())
  +        while(collectionIterator.hasNext())
           {
               relatedObj = collectionIterator.next();
               relatedObjKeys = new MtoNBroker.Key(pb.serviceBrokerHelper().getKeyValues(relatedCld,
relatedObj, true));
  @@ -192,38 +220,38 @@
   
           ValueContainer[] fkValues;
           Iterator iter = workList.iterator();
  -        while (iter.hasNext())
  +        while(iter.hasNext())
           {
  -            fkValues = ((MtoNBroker.Key)iter.next()).m_containers;
  +            fkValues = ((MtoNBroker.Key) iter.next()).m_containers;
               deleteStmt = pb.serviceSqlGenerator().getDeleteMNStatement(table, pkColumns,
fkColumns);
               pb.serviceJdbcAccess().executeUpdateSQL(deleteStmt, cld, pkValues, fkValues);
           }
       }
   
  -	/**
  -	 * @param m2n
  -	 */
  -	public void storeMtoNImplementor(MtoNImplementor m2n)
  -	{
  -		if(log.isDebugEnabled()) log.debug("Storing M2N implementor ["+m2n+"]");
  -		insertOrDeleteMtoNImplementor(m2n,true);
  -	}
  -
  -	/**
  -	 * @param m2n
  -	 */
  -	public void deleteMtoNImplementor(MtoNImplementor m2n)
  -	{
  -		if(log.isDebugEnabled()) log.debug("Deleting M2N implementor ["+m2n+"]");
  -		insertOrDeleteMtoNImplementor(m2n,false);
  -	}
  +    /**
  +     * @param m2n
  +     */
  +    public void storeMtoNImplementor(MtoNImplementor m2n)
  +    {
  +        if(log.isDebugEnabled()) log.debug("Storing M2N implementor [" + m2n + "]");
  +        insertOrDeleteMtoNImplementor(m2n, true);
  +    }
  +
  +    /**
  +     * @param m2n
  +     */
  +    public void deleteMtoNImplementor(MtoNImplementor m2n)
  +    {
  +        if(log.isDebugEnabled()) log.debug("Deleting M2N implementor [" + m2n + "]");
  +        insertOrDeleteMtoNImplementor(m2n, false);
  +    }
   
   
       /**
        * @see org.apache.ojb.broker.PersistenceBroker#deleteMtoNImplementor
        */
       private void insertOrDeleteMtoNImplementor(MtoNImplementor m2nImpl, boolean insert)
  -    	throws PersistenceBrokerException
  +            throws PersistenceBrokerException
       {
           //look for a collection descriptor on left  such as left.element-class-ref='right'
           DescriptorRepository dr = pb.getDescriptorRepository();
  @@ -233,9 +261,9 @@
           Object rightObject = m2nImpl.getRightObject();
           Class rightClass = rightObject.getClass();
   
  -        //
           //are written per class, maybe referencing abstract classes or interfaces
  -        //so let's look for collection descriptors on the left class and try to handle
extents on teh right class
  +        //so let's look for collection descriptors on the left class and try to
  +        // handle extents on teh right class
           ClassDescriptor leftCld = dr.getDescriptorFor(leftClass);
           ClassDescriptor rightCld = dr.getDescriptorFor(rightClass);
           Vector leftColds = leftCld.getCollectionDescriptors();
  @@ -250,29 +278,36 @@
           {
               //delete only one row
               ValueContainer[] leftPkValues = pb.serviceBrokerHelper().getKeyValues(leftCld,
leftObject);
  -            ValueContainer[] rightPkValues = pb.serviceBrokerHelper().getKeyValues(rightCld,rightObject);
  +            ValueContainer[] rightPkValues = pb.serviceBrokerHelper().getKeyValues(rightCld,
rightObject);
               String[] pkLeftColumns = wanted.getFksToThisClass();
               String[] pkRightColumns = wanted.getFksToItemClass();
               String table = wanted.getIndirectionTable();
  -            if(table == null) throw new PersistenceBrokerException("Can't remove MtoN implementor
withou an indirection table");
  +            if(table == null) throw new PersistenceBrokerException("Can't remove MtoN implementor
without an indirection table");
   
               String stmt = null;
  +            String[] cols = mergeColumns(pkLeftColumns, pkRightColumns);
  +            ValueContainer[] values = mergeContainer(leftPkValues, rightPkValues);
               if(insert)
               {
  -				stmt = pb.serviceSqlGenerator().getInsertMNStatement(table, pkLeftColumns, pkRightColumns);
  +                stmt = pb.serviceSqlGenerator().getInsertMNStatement(table, pkLeftColumns,
pkRightColumns);
  +                GenericObject gObj = new GenericObject(table, cols, values);
  +                if(!tempObjects.contains(gObj))
  +                {
  +                    pb.serviceJdbcAccess().executeUpdateSQL(stmt, leftCld, leftPkValues,
rightPkValues);
  +                    tempObjects.add(gObj);
  +                }
               }
               else
               {
  -				stmt = pb.serviceSqlGenerator().getDeleteMNStatement(table, pkLeftColumns, pkRightColumns);
  +                stmt = pb.serviceSqlGenerator().getDeleteMNStatement(table, pkLeftColumns,
pkRightColumns);
  +                pb.serviceJdbcAccess().executeUpdateSQL(stmt, leftCld, leftPkValues, rightPkValues);
               }
  -
  -            pb.serviceJdbcAccess().executeUpdateSQL(stmt, leftCld, leftPkValues, rightPkValues);
           }
       }
   
       private CollectionDescriptor findCollectionDescriptor(Class leftClass, Class rightClass,
Vector leftColds)
       {
  -        for (Iterator iter = leftColds.iterator(); iter.hasNext();)
  +        for(Iterator iter = leftColds.iterator(); iter.hasNext();)
           {
               CollectionDescriptor element = (CollectionDescriptor) iter.next();
   
  @@ -283,8 +318,24 @@
                   return element;
               }
           }
  -		throw new PersistenceBrokerException("Can't find reasonable collection descriptor for
MtoN implementor left["+leftClass
  -			+"] right["+rightClass+"]");
  +        throw new PersistenceBrokerException("Can't find reasonable collection descriptor
for MtoN implementor left[" + leftClass
  +                + "] right[" + rightClass + "]");
  +    }
  +
  +    private String[] mergeColumns(String[] first, String[] second)
  +    {
  +        String[] cols = new String[first.length + second.length];
  +        System.arraycopy(first, 0, cols, 0, first.length);
  +        System.arraycopy(second, 0, cols, first.length, second.length);
  +        return cols;
  +    }
  +
  +    private ValueContainer[] mergeContainer(ValueContainer[] first, ValueContainer[] second)
  +    {
  +        ValueContainer[] values = new ValueContainer[first.length + second.length];
  +        System.arraycopy(first, 0, values, 0, first.length);
  +        System.arraycopy(second, 0, values, first.length, second.length);
  +        return values;
       }
   
   
  @@ -304,7 +355,7 @@
           {
               m_containers = new ValueContainer[containers.length];
   
  -            for (int i = 0; i < containers.length; i++)
  +            for(int i = 0; i < containers.length; i++)
               {
                   Object value = containers[i].getValue();
                   JdbcType type = containers[i].getJdbcType();
  @@ -315,9 +366,9 @@
                   //
                   // could lead to problems when Floats are used as key
                   // converting to String could be a better alternative
  -                if (value instanceof Number)
  +                if(value instanceof Number)
                   {
  -                    value = new Long(((Number)value).longValue());
  +                    value = new Long(((Number) value).longValue());
                   }
   
                   m_containers[i] = new ValueContainer(value, type);
  @@ -326,11 +377,11 @@
   
           public boolean equals(Object other)
           {
  -            if (other == this)
  +            if(other == this)
               {
                   return true;
               }
  -            if (!(other instanceof Key))
  +            if(!(other instanceof Key))
               {
                   return false;
               }
  @@ -348,6 +399,126 @@
               hb.append(m_containers);
   
               return hb.toHashCode();
  +        }
  +    }
  +
  +
  +
  +    // ************************************************************************
  +    // inner class
  +    // ************************************************************************
  +    final class GenericObject implements Serializable
  +    {
  +        private String tablename;
  +        private String[] columnNames;
  +        private ValueContainer[] values;
  +
  +        public GenericObject(String tablename, String[] columnNames, ValueContainer[] values)
  +        {
  +            this.tablename = tablename;
  +            this.columnNames = columnNames;
  +            this.values = values;
  +            if(values != null && columnNames.length != values.length)
  +            {
  +                throw new OJBRuntimeException("Column name array and value array have NOT
same length");
  +            }
  +        }
  +
  +        public boolean equals(Object obj)
  +        {
  +            if(this == obj)
  +            {
  +                return true;
  +            }
  +            boolean result = false;
  +            if(obj instanceof GenericObject)
  +            {
  +                GenericObject other = (GenericObject) obj;
  +                if(result = (tablename.equalsIgnoreCase(other.tablename)
  +                        && (columnNames != null)
  +                        && (other.columnNames != null)
  +                        && (columnNames.length == other.columnNames.length)))
  +                {
  +                    for (int i = 0; i < columnNames.length; i++)
  +                    {
  +                        // System.out.println("## test: " + this);
  +                        int otherIndex = other.indexForColumn(columnNames[i]);
  +                        if(otherIndex < 0)
  +                        {
  +                            result = false;
  +                            break;
  +                        }
  +                        result = result && values[i].equals(other.values[otherIndex]);
  +                        if(!result) break;
  +                    }
  +    //                if(result)
  +    //                {
  +    //                    System.out.println("## Match: " + this);
  +    //                }
  +                }
  +            }
  +            return result;
  +        }
  +
  +        int indexForColumn(String name)
  +        {
  +            int result = -1;
  +            for (int i = 0; i < columnNames.length; i++)
  +            {
  +                if(columnNames[i].equals(name))
  +                {
  +                    result = i;
  +                    break;
  +                }
  +            }
  +            return result;
  +        }
  +
  +        public int hashCode()
  +        {
  +            return super.hashCode();
  +        }
  +
  +        public ValueContainer getValueFor(String columnName)
  +        {
  +            try
  +            {
  +                return values[indexForColumn(columnName)];
  +            }
  +            catch(Exception e)
  +            {
  +                throw new OJBRuntimeException("Can't find value for column " + columnName
  +                        + (indexForColumn(columnName) < 0 ? ". Column name was not found"
: ""), e);
  +            }
  +        }
  +
  +        public String getTablename()
  +        {
  +            return tablename;
  +        }
  +
  +        public String[] getColumnNames()
  +        {
  +            return columnNames;
  +        }
  +
  +        public ValueContainer[] getValues()
  +        {
  +            return values;
  +        }
  +
  +        public void setValues(ValueContainer[] values)
  +        {
  +            this.values = values;
  +        }
  +
  +        public String toString()
  +        {
  +            return new ToStringBuilder(this)
  +                    .append("tableName", tablename)
  +                    .append("columnNames", columnNames)
  +                    .append("values", values)
  +                    .toString();
           }
       }
   }
  
  
  
  1.83.2.3  +37 -38    db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java
  
  Index: PersistenceBrokerImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java,v
  retrieving revision 1.83.2.2
  retrieving revision 1.83.2.3
  diff -u -r1.83.2.2 -r1.83.2.3
  --- PersistenceBrokerImpl.java	27 Jul 2004 00:33:11 -0000	1.83.2.2
  +++ PersistenceBrokerImpl.java	21 Sep 2004 00:29:01 -0000	1.83.2.3
  @@ -50,6 +50,7 @@
   import org.apache.ojb.broker.cache.ObjectCacheFactory;
   import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
   import org.apache.ojb.broker.core.proxy.ProxyHelper;
  +import org.apache.ojb.broker.core.proxy.CollectionProxy;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
   import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
   import org.apache.ojb.broker.metadata.CollectionDescriptor;
  @@ -841,8 +842,8 @@
           - on insert we link and insert the referenced objects, because the proxy
           collection maybe "inherited" from the object before the PK was replaced
           */
  -        if(insert || !(referencedObjects instanceof CollectionProxyDefaultImpl
  -                        && !((CollectionProxyDefaultImpl) referencedObjects).isLoaded()))
  +        if(insert || !(referencedObjects instanceof CollectionProxy
  +                        && !((CollectionProxy) referencedObjects).isLoaded()))
           {
               // if referenced objects are null, assign empty list
               if(referencedObjects == null)
  @@ -857,48 +858,40 @@
               if we store an object with m:n reference and no references could be
               found, we remove all entires of given object in indirection table
               */
  -            Iterator referencedObjectsIterator = BrokerHelper.getCollectionIterator(referencedObjects);
  +            Iterator referencedObjectsIterator;
   
  -            if(!referencedObjectsIterator.hasNext())
  +            if(!onlyLink && cod.getCascadingStore() == ObjectReferenceDescriptor.CASCADE_OBJECT)
               {
  -                mtoNBroker.deleteMtoNImplementor(cod, obj);
  -            }
  -            else
  -            {
  -                Collection existingMtoNKeys;
  -                // use empty list on insert (by Andy Malakov)
  -                if (insert)
  -                {
  -                    existingMtoNKeys = Collections.EMPTY_LIST;
  -                }
  -                else
  -                {
  -                    existingMtoNKeys = mtoNBroker.getMtoNImplementor(cod, obj);
  -                    // remove all entries in indirection table which not be part of
  -                    // referenced objects
  -                    mtoNBroker.deleteMtoNImplementor(cod, obj, referencedObjectsIterator,
existingMtoNKeys);
  -                }
  -                // we can't reuse iterator
                   referencedObjectsIterator = BrokerHelper.getCollectionIterator(referencedObjects);
                   while (referencedObjectsIterator.hasNext())
                   {
  -                    Object refObj = referencedObjectsIterator.next();
  -                    // If cascade store is enabled and we don't want to link only,
  -                    // store depended upon object first to avoid FK violation
  -                    if(!onlyLink && cod.getCascadingStore() == ObjectReferenceDescriptor.CASCADE_OBJECT)
  -                    {
  -                        store(refObj);
  -                        // BRJ: store could have inserted MtoNImplementors
  -                        // so we need to read them to avoid ref. integrity
  -                        // violations
  -                        existingMtoNKeys = mtoNBroker.getMtoNImplementor(cod, obj);
  -                    }
  -                    // Now store indirection record
  -                    // BRJ: this could cause integrity problems because
  -                    // obj may not be stored depending on auto-update
  -                    mtoNBroker.storeMtoNImplementor(cod, obj, refObj, existingMtoNKeys);
  +                    store(referencedObjectsIterator.next());
                   }
               }
  +
  +            Collection existingMtoNKeys;
  +            if(!insert)
  +            {
  +                existingMtoNKeys = mtoNBroker.getMtoNImplementor(cod, obj);
  +                // we can't reuse iterator
  +                referencedObjectsIterator = BrokerHelper.getCollectionIterator(referencedObjects);
  +                // remove all entries in indirection table which not be part of referenced
objects
  +                mtoNBroker.deleteMtoNImplementor(cod, obj, referencedObjectsIterator, existingMtoNKeys);
  +            }
  +            else
  +            {
  +                existingMtoNKeys = Collections.EMPTY_LIST;
  +            }
  +            // we can't reuse iterator
  +            referencedObjectsIterator = BrokerHelper.getCollectionIterator(referencedObjects);
  +            while (referencedObjectsIterator.hasNext())
  +            {
  +                Object refObj = referencedObjectsIterator.next();
  +                // Now store indirection record
  +                // BRJ: this could cause integrity problems because
  +                // obj may not be stored depending on auto-update
  +                mtoNBroker.storeMtoNImplementor(cod, obj, refObj, existingMtoNKeys);
  +            }
           }
       }
   
  @@ -1894,6 +1887,12 @@
           nowStoring.clear();
           objectCache.localClear();
           deletedDuringTransaction.clear();
  +        /*
  +        arminw:
  +        for better performance I don't register MtoNBroker as listner,
  +        so use this method to reset on commit/rollback
  +        */
  +        mtoNBroker.reset();
       }
   
       /**
  
  
  
  No                   revision
  No                   revision
  1.7.2.2   +328 -6    db-ojb/src/test/org/apache/ojb/broker/M2NTest.java
  
  Index: M2NTest.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/test/org/apache/ojb/broker/M2NTest.java,v
  retrieving revision 1.7.2.1
  retrieving revision 1.7.2.2
  diff -u -r1.7.2.1 -r1.7.2.2
  --- M2NTest.java	27 Jul 2004 00:31:50 -0000	1.7.2.1
  +++ M2NTest.java	21 Sep 2004 00:29:02 -0000	1.7.2.2
  @@ -1,6 +1,8 @@
   package org.apache.ojb.broker;
   
   import org.apache.commons.lang.builder.ToStringBuilder;
  +import org.apache.commons.lang.time.StopWatch;
  +import org.apache.commons.lang.ClassUtils;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
   import org.apache.ojb.broker.metadata.CollectionDescriptor;
   import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
  @@ -12,6 +14,7 @@
   import java.util.ArrayList;
   import java.util.Collection;
   import java.util.Iterator;
  +import java.util.List;
   
   /**
    * Test (non-decomposed) M:N relations.
  @@ -29,6 +32,9 @@
       static final int LINK = ObjectReferenceDescriptor.CASCADE_LINK;
       static final int OBJECT = ObjectReferenceDescriptor.CASCADE_OBJECT;
   
  +    int actorCount = 200;
  +    int movieCount = 100;
  +
       public static void main(String[] args)
       {
           junit.textui.TestRunner.main(new String[]{M2NTest.class.getName()});
  @@ -45,6 +51,266 @@
           super.tearDown();
       }
   
  +    public void testMassStoreUpdateAutomatic()
  +    {
  +
  +        long testPeriod = 0;
  +
  +        String postfix = "testMassStoreUpdateAutomatic_" + System.currentTimeMillis();
  +        changeMovieCollectionDescriptorTo(true, OBJECT, OBJECT, false);
  +        changeActorCollectionDescriptorTo(true, OBJECT, OBJECT, false);
  +
  +        Movie movie = buildMovieWithActors(postfix, actorCount);
  +        Actor actor = buildActorWithMovies(postfix, movieCount);
  +
  +        List actors = new ArrayList(movie.getActors());
  +        actors.add(actor);
  +        movie.setActors(actors);
  +
  +        MovieManageableCollection movies = actor.getMovies();
  +        movies.add(movie);
  +
  +        StopWatch watch = new StopWatch();
  +        watch.start();
  +        broker.beginTransaction();
  +        broker.store(movie);
  +        broker.commitTransaction();
  +        watch.stop();
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateAutomatic] Time to store "+(actorCount + movieCount)+"
m:n objects=" + watch.getTime());
  +        testPeriod += watch.getTime();
  +
  +        watch.reset();
  +        watch.start();
  +        Query queryMovie = movieQuery(postfix);
  +        Collection resultMovie = broker.getCollectionByQuery(queryMovie);
  +        assertEquals(movieCount + 1, resultMovie.size());
  +        watch.stop();
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateAutomatic] Time to query "+movieCount+" m:n objects="
+ watch.getTime());
  +        testPeriod += watch.getTime();
  +
  +        watch.reset();
  +        watch.start();
  +        Query queryActor = actorQuery(postfix);
  +        Collection resultActor = broker.getCollectionByQuery(queryActor);
  +        assertEquals(actorCount + 1, resultActor.size());
  +        watch.stop();
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateAutomatic] Time to query "+actorCount+" m:n objects="
+ watch.getTime());
  +        testPeriod += watch.getTime();
  +
  +        Query queryRole = roleQueryActorOrMovieMatch(actor, movie);
  +        Collection resultRole = broker.getCollectionByQuery(queryRole);
  +        assertEquals(actorCount + movieCount + 1, resultRole.size());
  +
  +        //*****************************
  +        // update movie
  +        movie.setActors(new ArrayList());
  +        watch.reset();
  +        watch.start();
  +        broker.beginTransaction();
  +        broker.store(movie);
  +        broker.commitTransaction();
  +        watch.stop();
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateAutomatic] Time to update object with "+actorCount
+ " m:n objects=" + watch.getTime());
  +        testPeriod += watch.getTime();
  +        //*****************************
  +
  +        broker.clearCache();
  +        Identity oid = new Identity(movie, broker);
  +        movie = (Movie) broker.getObjectByIdentity(oid);
  +
  +        resultMovie = broker.getCollectionByQuery(queryMovie);
  +        assertEquals(movieCount + 1, resultMovie.size());
  +
  +        resultActor = broker.getCollectionByQuery(queryActor);
  +        assertEquals(actorCount + 1, resultActor.size());
  +
  +        resultRole = broker.getCollectionByQuery(queryRole);
  +        assertEquals(movieCount, resultRole.size());
  +
  +        assertNotNull(movie);
  +        assertEquals(0, movie.getActors().size());
  +
  +        //*****************************
  +        // remove actor
  +        movie.setActors(new ArrayList());
  +        watch.reset();
  +        watch.start();
  +        broker.beginTransaction();
  +        broker.delete(actor);
  +        broker.commitTransaction();
  +        watch.stop();
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateAutomatic] Time to remove object with "+ movieCount
+ " m:n objects=" + watch.getTime());
  +        testPeriod += watch.getTime();
  +        //*****************************
  +
  +        broker.clearCache();
  +        oid = new Identity(actor, broker);
  +        actor = (Actor) broker.getObjectByIdentity(oid);
  +
  +        resultMovie = broker.getCollectionByQuery(queryMovie);
  +        assertEquals(0, resultMovie.size());
  +
  +        // we never delete these actor objects
  +        resultActor = broker.getCollectionByQuery(queryActor);
  +        assertEquals(actorCount, resultActor.size());
  +
  +        resultRole = broker.getCollectionByQuery(queryRole);
  +        assertEquals(0, resultRole.size());
  +
  +        assertNull(actor);
  +
  +        broker.beginTransaction();
  +        broker.delete(movie);
  +        broker.commitTransaction();
  +
  +        resultMovie = broker.getCollectionByQuery(queryMovie);
  +        assertEquals(0, resultMovie.size());
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateAutomatic] Total test time is "+ testPeriod+" ms");
  +        System.out.println("");
  +    }
  +
  +
  +    public void testMassStoreUpdateLinking()
  +    {
  +        long testPeriod = 0;
  +
  +        String postfix = "testMassStoreUpdateLinking" + System.currentTimeMillis();
  +        changeMovieCollectionDescriptorTo(true, NONE, OBJECT, false);
  +        changeActorCollectionDescriptorTo(true, NONE, OBJECT, false);
  +
  +        Movie movie = buildMovieWithActors(postfix, actorCount);
  +        Actor actor = buildActorWithMovies(postfix, movieCount);
  +
  +        List actors = new ArrayList(movie.getActors());
  +        actors.add(actor);
  +        movie.setActors(actors);
  +
  +        MovieManageableCollection movies = actor.getMovies();
  +        movies.add(movie);
  +
  +        StopWatch watch = new StopWatch();
  +        watch.start();
  +        broker.beginTransaction();
  +        broker.store(movie);
  +        for(int i = 0; i < actors.size(); i++)
  +        {
  +            broker.store(actors.get(i));
  +        }
  +        MovieManageableCollection actorMovies = actor.getMovies();
  +        for(int i = 0; i < actorMovies.size(); i++)
  +        {
  +             broker.store(actorMovies.get(i));
  +        }
  +        broker.serviceBrokerHelper().link(movie, true);
  +        broker.serviceBrokerHelper().link(actor, true);
  +        broker.commitTransaction();
  +        watch.stop();
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateLinking] Time to store "+(actorCount + movieCount)+"
m:n objects=" + watch.getTime());
  +        testPeriod += watch.getTime();
  +
  +        watch.reset();
  +        watch.start();
  +        Query queryMovie = movieQuery(postfix);
  +        Collection resultMovie = broker.getCollectionByQuery(queryMovie);
  +        assertEquals(movieCount + 1, resultMovie.size());
  +        watch.stop();
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateLinking] Time to query "+movieCount+" m:n objects="
+ watch.getTime());
  +        testPeriod += watch.getTime();
  +
  +        watch.reset();
  +        watch.start();
  +        Query queryActor = actorQuery(postfix);
  +        Collection resultActor = broker.getCollectionByQuery(queryActor);
  +        assertEquals(actorCount + 1, resultActor.size());
  +        watch.stop();
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateLinking] Time to query "+actorCount+" m:n objects="
+ watch.getTime());
  +        testPeriod += watch.getTime();
  +
  +        Query queryRole = roleQueryActorOrMovieMatch(actor, movie);
  +        Collection resultRole = broker.getCollectionByQuery(queryRole);
  +        assertEquals(actorCount + movieCount + 1, resultRole.size());
  +
  +        //*****************************
  +        // update movie
  +        movie.setActors(new ArrayList());
  +        watch.reset();
  +        watch.start();
  +        broker.beginTransaction();
  +        broker.serviceBrokerHelper().unlink(movie);
  +        broker.store(movie);
  +        broker.serviceBrokerHelper().link(movie, false);
  +        broker.commitTransaction();
  +        watch.stop();
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateLinking] Time to update object with "+actorCount
+ " m:n objects=" + watch.getTime());
  +        testPeriod += watch.getTime();
  +        //*****************************
  +
  +        broker.clearCache();
  +        Identity oid = new Identity(movie, broker);
  +        movie = (Movie) broker.getObjectByIdentity(oid);
  +
  +        resultMovie = broker.getCollectionByQuery(queryMovie);
  +        assertEquals(movieCount + 1, resultMovie.size());
  +
  +        resultActor = broker.getCollectionByQuery(queryActor);
  +        assertEquals(actorCount + 1, resultActor.size());
  +
  +        resultRole = broker.getCollectionByQuery(queryRole);
  +        assertEquals(movieCount, resultRole.size());
  +
  +        assertNotNull(movie);
  +        assertEquals(0, movie.getActors().size());
  +
  +        //*****************************
  +        // remove actor
  +        movie.setActors(new ArrayList());
  +        watch.reset();
  +        watch.start();
  +        broker.beginTransaction();
  +        broker.delete(actor);
  +        broker.commitTransaction();
  +        watch.stop();
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateLinking] Time to remove object with "+ movieCount
+ " m:n objects=" + watch.getTime());
  +        testPeriod += watch.getTime();
  +        //*****************************
  +
  +        broker.clearCache();
  +        oid = new Identity(actor, broker);
  +        actor = (Actor) broker.getObjectByIdentity(oid);
  +
  +        resultMovie = broker.getCollectionByQuery(queryMovie);
  +        assertEquals(0, resultMovie.size());
  +
  +        // we never delete these actor objects
  +        resultActor = broker.getCollectionByQuery(queryActor);
  +        assertEquals(actorCount, resultActor.size());
  +
  +        resultRole = broker.getCollectionByQuery(queryRole);
  +        assertEquals(0, resultRole.size());
  +
  +        assertNull(actor);
  +
  +        broker.beginTransaction();
  +        broker.delete(movie);
  +        broker.commitTransaction();
  +
  +        resultMovie = broker.getCollectionByQuery(queryMovie);
  +        assertEquals(0, resultMovie.size());
  +        System.out.println("[" + ClassUtils.getShortClassName(this.getClass())
  +                + "#testMassStoreUpdateLinking] Total test time is "+ testPeriod+" ms");
  +        System.out.println("");
  +    }
   
       public void testAutoUpdateDeleteSettings()
       {
  @@ -518,16 +784,16 @@
   
       public void testAddNewEntriesTTTF()
       {
  -        changeMovieCollectionDescriptorTo(true, OBJECT, NONE, false);
  -        changeActorCollectionDescriptorTo(true, OBJECT, NONE, false);
  +        changeMovieCollectionDescriptorTo(true, OBJECT, OBJECT, false);
  +        changeActorCollectionDescriptorTo(true, OBJECT, OBJECT, false);
           doTestStoreUpdateTTXX();
       }
   
       public void testAddNewEntriesTTTT()
       {
  -        changeMovieCollectionDescriptorTo(true, OBJECT, NONE, true);
  -        // default proxy does not work for user defined collection 
  -        changeActorCollectionDescriptorTo(true, OBJECT, NONE, false);
  +        changeMovieCollectionDescriptorTo(true, OBJECT, OBJECT, true);
  +        // default proxy does not work for user defined collection
  +        changeActorCollectionDescriptorTo(true, OBJECT, OBJECT, false);
           doTestStoreUpdateTTXX();
       }
   
  @@ -657,6 +923,28 @@
           return q;
       }
   
  +    Query roleQueryActorOrMovieMatch(Actor actor, Movie movie)
  +    {
  +        Criteria c_1 = new Criteria();
  +        Criteria c_2 = new Criteria();
  +        if(actor != null) c_1.addEqualTo("actorId", actor.getId());
  +        if(movie != null)
  +        {
  +            c_2.addEqualTo("movieIntId", movie.getIdInt());
  +            c_2.addEqualTo("movieStrId", movie.getIdStr());
  +        }
  +        if(actor != null)
  +        {
  +            c_2.addOrCriteria(c_1);
  +        }
  +        else
  +        {
  +            c_2 = c_1;
  +        }
  +        Query q = QueryFactory.newQuery(Role.class, c_2);
  +        return q;
  +    }
  +
       /**
        * Returns 1 movie object with 3 actor objects
        */
  @@ -675,6 +963,40 @@
           list.add(a3);
           m.setActors(list);
           return m;
  +    }
  +
  +    /**
  +     * Returns 1 movie object with 3 actor objects
  +     */
  +    Movie buildMovieWithActors(String postfixId, int actorCount)
  +    {
  +        Movie m = new MovieImpl(postfixId, "Movie with "+ actorCount+" actors_" + postfixId,
"none");
  +
  +        ArrayList list = new ArrayList();
  +        for(int i = 0; i < actorCount; i++)
  +        {
  +            Actor a = new Actor("A bad actor_" + postfixId);
  +            list.add(a);
  +        }
  +        m.setActors(list);
  +        return m;
  +    }
  +
  +    /**
  +     * Returns 1 movie object with 3 actor objects
  +     */
  +    Actor buildActorWithMovies(String postfixId, int movieCount)
  +    {
  +        Actor a = new Actor(postfixId+"_Actor play in "+ movieCount+" movies");
  +
  +        MovieManageableCollection list = new MovieManageableCollection();
  +        for(int i = 0; i < movieCount; i++)
  +        {
  +            Movie m  = new MovieImpl(postfixId, "A bad movie_" + postfixId, "none");
  +            list.add(m);
  +        }
  +        a.setMovies(list);
  +        return a;
       }
   
       /**
  
  
  
  No                   revision
  No                   revision
  1.54.2.13 +3 -1      db-ojb/release-notes.txt
  
  Index: release-notes.txt
  ===================================================================
  RCS file: /home/cvs/db-ojb/release-notes.txt,v
  retrieving revision 1.54.2.12
  retrieving revision 1.54.2.13
  diff -u -r1.54.2.12 -r1.54.2.13
  --- release-notes.txt	20 Sep 2004 13:43:32 -0000	1.54.2.12
  +++ release-notes.txt	21 Sep 2004 00:29:02 -0000	1.54.2.13
  @@ -21,6 +21,7 @@
     correspond to your J2SE version. E.g. for J2SE 1.3 use the J2EE 1.3 SDK which
     you can get from here: http://java.sun.com/j2ee/1.3/index.jsp
   - ODMG-api improved, up to 30% better performance
  +- Performance improvement in handling of m:n relations
   
   CHANGES:
   - !!!In managed enviroments the org.odmg.Transaction#abort() call no longer throws an
  @@ -39,6 +40,7 @@
   under http://issues.apache.org/scarab/servlet/scarab/issues/id/OJBxxx
   to see details for a bug with id OJBxxx.
   
  +- Fix key constraint problems when insert m:n relation manually via "linking"
   - Fix bug in SequenceManagerNativeImpl used to support DB identity columns, make counter
for
     temporary keys static to prevent lock not granted exceptions on insert of new objects.
   - odmg-api: if within a transaction the client returns a different instance of an already
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org


Mime
View raw message