You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(22) |
Nov
(308) |
Dec
(131) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(369) |
Feb
(171) |
Mar
(236) |
Apr
(187) |
May
(218) |
Jun
(217) |
Jul
(127) |
Aug
(448) |
Sep
(270) |
Oct
(231) |
Nov
(422) |
Dec
(255) |
2004 |
Jan
(111) |
Feb
(73) |
Mar
(338) |
Apr
(351) |
May
(349) |
Jun
(495) |
Jul
(394) |
Aug
(1048) |
Sep
(499) |
Oct
(142) |
Nov
(269) |
Dec
(638) |
2005 |
Jan
(825) |
Feb
(1272) |
Mar
(593) |
Apr
(690) |
May
(950) |
Jun
(958) |
Jul
(767) |
Aug
(839) |
Sep
(525) |
Oct
(449) |
Nov
(585) |
Dec
(455) |
2006 |
Jan
(603) |
Feb
(656) |
Mar
(195) |
Apr
(114) |
May
(136) |
Jun
(100) |
Jul
(128) |
Aug
(68) |
Sep
(7) |
Oct
(1) |
Nov
(1) |
Dec
(8) |
2007 |
Jan
(4) |
Feb
(3) |
Mar
(8) |
Apr
(16) |
May
(5) |
Jun
(4) |
Jul
(6) |
Aug
(23) |
Sep
(15) |
Oct
(5) |
Nov
(7) |
Dec
(5) |
2008 |
Jan
(5) |
Feb
(1) |
Mar
(1) |
Apr
(5) |
May
(1) |
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
|
2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
|
2011 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
2012 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
(1) |
Jul
(1) |
Aug
(1) |
Sep
|
Oct
(2) |
Nov
(3) |
Dec
(2) |
2013 |
Jan
(1) |
Feb
|
Mar
(2) |
Apr
(1) |
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2014 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
(2) |
Jun
(1) |
Jul
|
Aug
(1) |
Sep
(1) |
Oct
|
Nov
(1) |
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
|
2016 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2017 |
Jan
(1) |
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
Author: ste...@jb... Date: 2006-06-27 22:53:39 -0400 (Tue, 27 Jun 2006) New Revision: 10060 Added: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BooleanLiteralNode.java trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.java Modified: trunk/Hibernate3/src/org/hibernate/dialect/Dialect.java trunk/Hibernate3/src/org/hibernate/dialect/MySQLDialect.java trunk/Hibernate3/src/org/hibernate/dialect/PostgreSQLDialect.java trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/LiteralNode.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/Node.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java trunk/Hibernate3/src/org/hibernate/impl/AbstractQueryImpl.java trunk/Hibernate3/test/org/hibernate/test/component/ComponentTest.java trunk/Hibernate3/test/org/hibernate/test/component/User.hbm.xml trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java trunk/Hibernate3/test/org/hibernate/test/hql/BulkManipulationTest.java trunk/Hibernate3/test/org/hibernate/test/hql/FooBarCopy.hbm.xml trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java trunk/Hibernate3/test/org/hibernate/test/hql/QueryTranslatorTestCase.java Log: HHH-1855 : HQL and boolean handling (literals and params); HHH-1858 : HQL and many-to-any; HHH-1861 : HQL and components Modified: trunk/Hibernate3/src/org/hibernate/dialect/Dialect.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/dialect/Dialect.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/dialect/Dialect.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -1060,4 +1060,20 @@ public LockingStrategy getLockingStrategy(Lockable lockable, LockMode lockMode) { return new SelectLockingStrategy( lockable, lockMode ); } + + /** + * Is this dialect known to support what ANSI-SQL terms "row value + * constructor" syntax; sometimes called tuple syntax. + * <p/> + * Basically, does it support syntax like + * "... where (FIRST_NAME, LAST_NAME) = ('Steve', 'Ebersole') ...". + * + * @return True if this SQL dialect is known to support "row value + * constructor" syntax; false otherwise. + * @since 3.2 + */ + public boolean supportsRowValueConstructorSyntax() { + // return false here, as most databases do not properly support this construct... + return false; + } } Modified: trunk/Hibernate3/src/org/hibernate/dialect/MySQLDialect.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/dialect/MySQLDialect.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/dialect/MySQLDialect.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -320,5 +320,8 @@ ResultSet rs = ps.getResultSet(); return rs; } - + + public boolean supportsRowValueConstructorSyntax() { + return true; + } } \ No newline at end of file Modified: trunk/Hibernate3/src/org/hibernate/dialect/PostgreSQLDialect.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/dialect/PostgreSQLDialect.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/dialect/PostgreSQLDialect.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -293,4 +293,7 @@ } }; + public boolean supportsRowValueConstructorSyntax() { + return true; + } } Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -45,8 +45,6 @@ import org.hibernate.hql.ast.tree.UpdateStatement; import org.hibernate.hql.ast.tree.Node; import org.hibernate.hql.ast.tree.OperatorNode; -import org.hibernate.hql.ast.tree.BinaryLogicOperatorNode; -import org.hibernate.hql.ast.tree.InLogicOperatorNode; import org.hibernate.hql.ast.util.ASTPrinter; import org.hibernate.hql.ast.util.ASTUtil; import org.hibernate.hql.ast.util.AliasGenerator; @@ -923,6 +921,7 @@ } protected void evaluateAssignment(AST eq) throws SemanticException { + prepareLogicOperator( eq ); Queryable persister = getCurrentFromClause().getFromElement().getQueryable(); evaluateAssignment( eq, persister, -1 ); } Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -39,6 +39,7 @@ import org.hibernate.hql.ast.tree.InLogicOperatorNode; import org.hibernate.hql.ast.tree.JavaConstantNode; import org.hibernate.hql.ast.tree.SessionFactoryAwareNode; +import org.hibernate.hql.ast.tree.BooleanLiteralNode; import java.lang.reflect.Constructor; @@ -117,9 +118,10 @@ case NUM_LONG: case NUM_DOUBLE: case QUOTED_STRING: + return LiteralNode.class; case TRUE: case FALSE: - return LiteralNode.class; + return BooleanLiteralNode.class; case JAVA_CONSTANT: return JavaConstantNode.class; case ORDER: Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -13,13 +13,14 @@ import org.hibernate.hql.antlr.SqlGeneratorBase; import org.hibernate.hql.ast.tree.MethodNode; import org.hibernate.hql.ast.tree.FromElement; -import org.hibernate.hql.ast.tree.JavaConstantNode; +import org.hibernate.hql.ast.tree.Node; /** * Generates SQL by overriding callback methods in the base class, which does * the actual SQL AST walking. * - * @author Joshua + * @author Joshua Davis + * @author Steve Ebersole */ public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter { /** @@ -45,8 +46,8 @@ } protected void out(AST n) { - if ( n instanceof JavaConstantNode ) { - out( ( ( JavaConstantNode ) n ).getSqlText() ); + if ( n instanceof Node ) { + out( ( ( Node ) n ).getRenderText( sessionFactory ) ); } else { super.out( n ); Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -2,14 +2,21 @@ import org.hibernate.type.Type; import org.hibernate.Hibernate; +import org.hibernate.TypeMismatchException; +import org.hibernate.HibernateException; +import org.hibernate.util.StringHelper; +import org.hibernate.hql.antlr.HqlSqlTokenTypes; +import org.hibernate.dialect.HSQLDialect; +import org.hibernate.engine.SessionFactoryImplementor; import antlr.SemanticException; +import antlr.collections.AST; /** * Contract for nodes representing binary operators. * * @author Steve Ebersole */ -public class BinaryLogicOperatorNode extends SqlNode implements BinaryOperatorNode { +public class BinaryLogicOperatorNode extends HqlSqlWalkerNode implements BinaryOperatorNode { /** * Performs the operator node initialization by seeking out any parameter * nodes and setting their expected type, if possible. @@ -23,16 +30,149 @@ if ( rhs == null ) { throw new SemanticException( "right-hand operand of a binary operator was null" ); } - if ( ExpectedTypeAwareNode.class.isAssignableFrom( lhs.getClass() ) - && SqlNode.class.isAssignableFrom( rhs.getClass() ) ) { - ( ( ExpectedTypeAwareNode ) lhs ).setExpectedType( ( ( SqlNode ) rhs ).getDataType() ); + + Type lhsType = extractDataType( lhs ); + Type rhsType = extractDataType( rhs ); + + if ( lhsType == null ) { + lhsType = rhsType; } - else if ( ExpectedTypeAwareNode.class.isAssignableFrom( rhs.getClass() ) - && SqlNode.class.isAssignableFrom( lhs.getClass() ) ) { - ( ( ExpectedTypeAwareNode ) rhs ).setExpectedType( ( ( SqlNode ) lhs ).getDataType() ); + if ( rhsType == null ) { + rhsType = lhsType; } + + if ( ExpectedTypeAwareNode.class.isAssignableFrom( lhs.getClass() ) ) { + ( ( ExpectedTypeAwareNode ) lhs ).setExpectedType( rhsType ); + } + if ( ExpectedTypeAwareNode.class.isAssignableFrom( rhs.getClass() ) ) { + ( ( ExpectedTypeAwareNode ) rhs ).setExpectedType( lhsType ); + } + + mutateRowValueConstructorSyntaxesIfNecessary( lhsType, rhsType ); } + protected final void mutateRowValueConstructorSyntaxesIfNecessary(Type lhsType, Type rhsType) { + // TODO : this really needs to be delayed unitl after we definitively know all node types + // where this is currently a problem is parameters for which where we cannot unequivocally + // resolve an expected type + SessionFactoryImplementor sessionFactory = getSessionFactoryHelper().getFactory(); + if ( lhsType != null && rhsType != null ) { + int lhsColumnSpan = lhsType.getColumnSpan( sessionFactory ); + if ( lhsColumnSpan != rhsType.getColumnSpan( sessionFactory ) ) { + throw new TypeMismatchException( + "left and right hand sides of a binary logic operator were incompatibile [" + + lhsType.getName() + " : "+ rhsType.getName() + "]" + ); + } + if ( lhsColumnSpan > 1 ) { + // for dialects which are known to not support ANSI-SQL row-value-constructor syntax, + // we should mutate the tree. + if ( !sessionFactory.getDialect().supportsRowValueConstructorSyntax() ) { + mutateRowValueConstructorSyntax( lhsColumnSpan ); + } + } + } + } + + /** + * Mutate the subtree relating to a row-value-constructor to instead use + * a series of ANDed predicates. This allows multi-column type comparisons + * and explicit row-value-constructor syntax even on databases which do + * not support row-value-constructor. + * <p/> + * For example, here we'd mutate "... where (col1, col2) = ('val1', 'val2) ..." to + * "... where col1 = 'val1' and col2 = 'val2' ..." + * + * @param valueElements The number of elements in the row value constructor list. + */ + private void mutateRowValueConstructorSyntax(int valueElements) { + // mutation depends on the types of nodes invloved... + int comparisonType = getType(); + String comparisonText = getText(); + setType( HqlSqlTokenTypes.AND ); + setText( "AND" ); + String[] lhsElementTexts = extractMutationTexts( getLeftHandOperand(), valueElements ); + String[] rhsElementTexts = extractMutationTexts( getRightHandOperand(), valueElements ); + + AST container = this; + for ( int i = valueElements - 1; i > 0; i-- ) { + + if ( i == 1 ) { + AST op1 = getASTFactory().create( comparisonType, comparisonText ); + AST lhs1 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, lhsElementTexts[0] ); + AST rhs1 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[0] ); + op1.setFirstChild( lhs1 ); + lhs1.setNextSibling( rhs1 ); + container.setFirstChild( op1 ); + AST op2 = getASTFactory().create( comparisonType, comparisonText ); + AST lhs2 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, lhsElementTexts[1] ); + AST rhs2 = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[1] ); + op2.setFirstChild( lhs2 ); + lhs2.setNextSibling( rhs2 ); + op1.setNextSibling( op2 ); + } + else { + AST op = getASTFactory().create( comparisonType, comparisonText ); + AST lhs = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, lhsElementTexts[i] ); + AST rhs = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, rhsElementTexts[i] ); + op.setFirstChild( lhs ); + lhs.setNextSibling( rhs ); + AST newContainer = getASTFactory().create( HqlSqlTokenTypes.AND, "AND" ); + container.setFirstChild( newContainer ); + newContainer.setNextSibling( op ); + container = newContainer; + } + } + } + + private static String[] extractMutationTexts(Node operand, int count) { + if ( operand instanceof ParameterNode ) { + String[] rtn = new String[count]; + for ( int i = 0; i < count; i++ ) { + rtn[i] = "?"; + } + return rtn; + } + else if ( operand.getType() == HqlSqlTokenTypes.VECTOR_EXPR ) { + String[] rtn = new String[ operand.getNumberOfChildren() ]; + int x = 0; + AST node = operand.getFirstChild(); + while ( node != null ) { + rtn[ x++ ] = node.getText(); + node = node.getNextSibling(); + } + return rtn; + } + else if ( operand instanceof SqlNode ) { + String nodeText = operand.getText(); + if ( nodeText.startsWith( "(" ) ) { + nodeText = nodeText.substring( 1 ); + } + if ( nodeText.endsWith( ")" ) ) { + nodeText = nodeText.substring( 0, nodeText.length() - 1 ); + } + String[] splits = StringHelper.split( ", ", nodeText ); + if ( count != splits.length ) { + throw new HibernateException( "SqlNode's text did not reference expected number of columns" ); + } + return splits; + } + else { + throw new HibernateException( "dont know how to extract row value elements from node : " + operand ); + } + } + + protected Type extractDataType(Node operand) { + Type type = null; + if ( operand instanceof SqlNode ) { + type = ( ( SqlNode ) operand ).getDataType(); + } + if ( type == null && operand instanceof ExpectedTypeAwareNode ) { + type = ( ( ExpectedTypeAwareNode ) operand ).getExpectedType(); + } + return type; + } + public Type getDataType() { // logic operators by definition resolve to booleans return Hibernate.BOOLEAN; Added: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BooleanLiteralNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BooleanLiteralNode.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BooleanLiteralNode.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -0,0 +1,50 @@ +package org.hibernate.hql.ast.tree; + +import org.hibernate.type.Type; +import org.hibernate.type.BooleanType; +import org.hibernate.Hibernate; +import org.hibernate.QueryException; +import org.hibernate.engine.SessionFactoryImplementor; + +/** + * Represents a boolean literal within a query. + * + * @author Steve Ebersole + */ +public class BooleanLiteralNode extends LiteralNode implements ExpectedTypeAwareNode { + private Type expectedType; + + public Type getDataType() { + return expectedType == null ? Hibernate.BOOLEAN : expectedType; + } + + public BooleanType getTypeInternal() { + return ( BooleanType ) getDataType(); + } + + public Boolean getValue() { + return getType() == TRUE ? Boolean.TRUE : Boolean.FALSE; + } + + /** + * Expected-types really only pertinent here for boolean literals... + * + * @param expectedType + */ + public void setExpectedType(Type expectedType) { + this.expectedType = expectedType; + } + + public Type getExpectedType() { + return expectedType; + } + + public String getRenderText(SessionFactoryImplementor sessionFactory) { + try { + return getTypeInternal().objectToSQLString( getValue(), sessionFactory.getDialect() ); + } + catch( Throwable t ) { + throw new QueryException( "Unable to render boolean literal value", t ); + } + } +} Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/FromElementType.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -381,7 +381,14 @@ } return collectionPropertyMapping; } - if ( queryableCollection.getElementType().isComponentType() ) { // Collection of components. + if ( queryableCollection.getElementType().isAnyType() ) { + // collection of <many-to-any/> mappings... + // used to circumvent the component-collection check below... + return queryableCollection; + + } + if ( queryableCollection.getElementType().isComponentType() ) { + // Collection of components. if ( propertyName.equals( EntityPersister.ENTITY_ID ) ) { return ( PropertyMapping ) queryableCollection.getOwnerEntityPersister(); } Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -48,11 +48,6 @@ this.factory = factory; } - public String getSqlText() { - Type type = expectedType == null ? heuristicType : expectedType; - return resolveToLiteralString( type ); - } - private String resolveToLiteralString(Type type) { try { LiteralType literalType = ( LiteralType ) type; @@ -63,4 +58,9 @@ throw new QueryException( QueryTranslator.ERROR_CANNOT_FORMAT_LITERAL + constantExpression, t ); } } + + public String getRenderText(SessionFactoryImplementor sessionFactory) { + Type type = expectedType == null ? heuristicType : expectedType; + return resolveToLiteralString( type ); + } } Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/LiteralNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/LiteralNode.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/LiteralNode.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -38,5 +38,4 @@ return null; } } - } Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/Node.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/Node.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/Node.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -3,12 +3,13 @@ import antlr.collections.AST; import antlr.Token; import org.hibernate.util.StringHelper; +import org.hibernate.engine.SessionFactoryImplementor; /** - * Generic AST Node. - * User: Joshua Davis<br> - * Date: Sep 23, 2005<br> - * Time: 12:20:53 PM<br> + * Base node class for use by Hibernate within its AST trees. + * + * @author Joshua Davis + * @author Steve Ebersole */ public class Node extends antlr.CommonAST { private String filename; @@ -24,6 +25,17 @@ super(tok); // This will call initialize(tok)! } + /** + * Retrieve the text to be used for rendering this particular node. + * + * @param sessionFactory The session factory + * @return The text to use for rendering + */ + public String getRenderText(SessionFactoryImplementor sessionFactory) { + // The basic implementation is to simply use the node's text + return getText(); + } + public void initialize(Token tok) { super.initialize(tok); filename = tok.getFilename(); @@ -34,9 +46,8 @@ } public void initialize(AST t) { - super.initialize(t); - if (t instanceof Node) - { + super.initialize( t ); + if ( t instanceof Node ) { Node n = (Node)t; filename = n.filename; line = n.line; Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -3,6 +3,7 @@ import org.hibernate.param.ParameterSpecification; import org.hibernate.type.Type; +import org.hibernate.engine.SessionFactoryImplementor; /** * Implementation of ParameterNode. @@ -32,4 +33,20 @@ public Type getExpectedType() { return getHqlParameterSpecification() == null ? null : getHqlParameterSpecification().getExpectedType(); } + + public String getRenderText(SessionFactoryImplementor sessionFactory) { + int count = 0; + if ( getExpectedType() != null && ( count = getExpectedType().getColumnSpan( sessionFactory ) ) > 1 ) { + StringBuffer buffer = new StringBuffer(); + buffer.append( "(?" ); + for ( int i = 1; i < count; i++ ) { + buffer.append( ", ?" ); + } + buffer.append( ")" ); + return buffer.toString(); + } + else { + return "?"; + } + } } Modified: trunk/Hibernate3/src/org/hibernate/impl/AbstractQueryImpl.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/impl/AbstractQueryImpl.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/src/org/hibernate/impl/AbstractQueryImpl.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -385,6 +385,14 @@ return this; } + protected Type determineType(int paramPosition, Object paramValue, Type defaultType) { + Type type = parameterMetadata.getOrdinalParameterExpectedType( paramPosition + 1 ); + if ( type == null ) { + type = defaultType; + } + return type; + } + protected Type determineType(int paramPosition, Object paramValue) throws HibernateException { Type type = parameterMetadata.getOrdinalParameterExpectedType( paramPosition + 1 ); if ( type == null ) { @@ -393,6 +401,14 @@ return type; } + protected Type determineType(String paramName, Object paramValue, Type defaultType) { + Type type = parameterMetadata.getNamedParameterExpectedType( paramName ); + if ( type == null ) { + type = defaultType; + } + return type; + } + protected Type determineType(String paramName, Object paramValue) throws HibernateException { Type type = parameterMetadata.getNamedParameterExpectedType( paramName ); if ( type == null ) { @@ -448,7 +464,9 @@ } public Query setBoolean(int position, boolean val) { - setParameter(position, val ? Boolean.TRUE : Boolean.FALSE, Hibernate.BOOLEAN); + Boolean valueToUse = val ? Boolean.TRUE : Boolean.FALSE; + Type typeToUse = determineType( position, valueToUse, Hibernate.BOOLEAN ); + setParameter( position, valueToUse, typeToUse ); return this; } @@ -543,7 +561,9 @@ } public Query setBoolean(String name, boolean val) { - setParameter(name, val ? Boolean.TRUE : Boolean.FALSE, Hibernate.BOOLEAN); + Boolean valueToUse = val ? Boolean.TRUE : Boolean.FALSE; + Type typeToUse = determineType( name, valueToUse, Hibernate.BOOLEAN ); + setParameter( name, valueToUse, typeToUse ); return this; } Modified: trunk/Hibernate3/test/org/hibernate/test/component/ComponentTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/component/ComponentTest.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/test/org/hibernate/test/component/ComponentTest.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -14,6 +14,7 @@ import org.hibernate.dialect.HSQLDialect; import org.hibernate.dialect.Oracle9Dialect; import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.dialect.SQLServerDialect; import org.hibernate.test.TestCase; /** @@ -89,6 +90,28 @@ t.commit(); s.close(); } + + public void testComponentQueries() { +// if ( !dialectSupportsRowValueConstructorSyntax() ) { +// return; +// } + Session s = openSession(); + Transaction t = s.beginTransaction(); + Employee emp = new Employee(); + emp.setHireDate( new Date() ); + emp.setPerson( new Person() ); + emp.getPerson().setName( "steve" ); + emp.getPerson().setDob( new Date() ); + s.save( emp ); + + s.createQuery( "from Employee e where e.person = :p and 1 = 1 and 2=2" ).setParameter( "p", emp.getPerson() ).list(); + s.createQuery( "from Employee e where :p = e.person" ).setParameter( "p", emp.getPerson() ).list(); + s.createQuery( "from Employee e where e.person = ('steve', current_timestamp)" ).list(); + + s.delete( emp ); + t.commit(); + s.close(); + } public void testComponentFormulaQuery() { @@ -110,7 +133,7 @@ t.commit(); s.close(); } - + public void testNamedQuery() { if ( getDialect() instanceof PostgreSQLDialect ) return; //postgres got no year() function if ( getDialect() instanceof Oracle9Dialect ) return; //oracle got no year() function Modified: trunk/Hibernate3/test/org/hibernate/test/component/User.hbm.xml =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/component/User.hbm.xml 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/test/org/hibernate/test/component/User.hbm.xml 2006-06-28 02:53:39 UTC (rev 10060) @@ -25,6 +25,17 @@ update="false"/> </component> </class> + + <class name="Employee" table="T_EMP"> + <id name="id" type="long" column="ID"> + <generator class="increment"/> + </id> + <property name="hireDate" type="date" column="HIRE_DATE"/> + <component name="person"> + <property name="name" update="false" not-null="true"/> + <property name="dob" update="false" not-null="true"/> + </component> + </class> <query name="userNameIn"><![CDATA[from User where person.name in (:nameList) or userName in (:nameList)]]></query> Modified: trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/test/org/hibernate/test/hql/ASTParserLoadingTest.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -31,6 +31,12 @@ import org.hibernate.dialect.Oracle9Dialect; import org.hibernate.stat.QueryStatistics; import org.hibernate.test.TestCase; +import org.hibernate.test.any.PropertyValue; +import org.hibernate.test.any.StringPropertyValue; +import org.hibernate.test.any.IntegerPropertyValue; +import org.hibernate.test.any.PropertySet; +import org.hibernate.test.legacy.Bar; +import org.hibernate.test.legacy.One; import org.hibernate.test.cid.Customer; import org.hibernate.test.cid.LineItem; import org.hibernate.test.cid.Order; @@ -68,14 +74,15 @@ protected String[] getMappings() { // Make sure we are using the new AST parser translator... System.setProperty( Environment.QUERY_TRANSLATOR, "org.hibernate.hql.ast.ASTQueryTranslatorFactory" ); - return new String[]{ - "hql/Animal.hbm.xml", - "hql/FooBarCopy.hbm.xml", - "batchfetch/ProductLine.hbm.xml", - "cid/Customer.hbm.xml", - "cid/Order.hbm.xml", - "cid/LineItem.hbm.xml", - "cid/Product.hbm.xml" + return new String[] { + "hql/Animal.hbm.xml", + "hql/FooBarCopy.hbm.xml", + "batchfetch/ProductLine.hbm.xml", + "cid/Customer.hbm.xml", + "cid/Order.hbm.xml", + "cid/LineItem.hbm.xml", + "cid/Product.hbm.xml", + "any/Properties.hbm.xml" }; } @@ -86,6 +93,62 @@ } + public void testComponentQueries() { + Session s = openSession(); + s.beginTransaction(); + + // Test the ability to perform comparisions between component values + s.createQuery( "from Human h where h.name = h.name" ).list(); + s.createQuery( "from Human h where h.name = :name" ).setParameter( "name", new Name() ).list(); + s.createQuery( "from Human where name = :name" ).setParameter( "name", new Name() ).list(); + s.createQuery( "from Human h where :name = h.name" ).setParameter( "name", new Name() ).list(); + s.createQuery( "from Human h where :name <> h.name" ).setParameter( "name", new Name() ).list(); + + // Test the ability to perform comparisions between a component and an explicit row-value + s.createQuery( "from Human h where h.name = ('John', 'X', 'Doe')" ).list(); + s.createQuery( "from Human h where ('John', 'X', 'Doe') = h.name" ).list(); + s.createQuery( "from Human h where ('John', 'X', 'Doe') <> h.name" ).list(); + s.createQuery( "from Human h where ('John', 'X', 'Doe') >= h.name" ).list(); + + s.getTransaction().commit(); + s.close(); + } + + public void testAnyMappingReference() { + Session s = openSession(); + s.beginTransaction(); + + PropertyValue redValue = new StringPropertyValue( "red" ); + PropertyValue lonliestNumberValue = new IntegerPropertyValue( 1 ); + + Long id; + PropertySet ps = new PropertySet( "my properties" ); + ps.setSomeSpecificProperty( redValue ); + ps.getGeneralProperties().put( "the lonliest number", lonliestNumberValue ); + ps.getGeneralProperties().put( "i like", new StringPropertyValue( "pina coladas" ) ); + ps.getGeneralProperties().put( "i also like", new StringPropertyValue( "getting caught in the rain" ) ); + s.save( ps ); + + s.getTransaction().commit(); + id = ps.getId(); + s.clear(); + s.beginTransaction(); + + // TODO : setEntity() currently will not work here, but that would be *very* nice + // does not work because the corresponding EntityType is then used as the "bind type" rather + // than the "discovered" AnyType... + s.createQuery( "from PropertySet p where p.someSpecificProperty = :ssp" ).setParameter( "ssp", redValue ).list(); + + s.createQuery( "from PropertySet p where p.someSpecificProperty.id is not null" ).list(); + + s.createQuery( "from PropertySet p join p.generalProperties gp where gp.id is not null" ).list(); + + s.delete( s.load( PropertySet.class, id ) ); + + s.getTransaction().commit(); + s.close(); + } + public void testJdkEnumStyleEnumConstant() throws Exception { Session s = openSession(); s.beginTransaction(); Added: trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.hbm.xml 2006-06-28 02:53:39 UTC (rev 10060) @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!DOCTYPE hibernate-mapping SYSTEM "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > + +<hibernate-mapping package="org.hibernate.test.hql" default-access="field"> + + <class name="BooleanLiteralEntity"> + <id name="id"> + <generator class="native"/> + </id> + <property name="yesNoBoolean" column="Y_N_BOOL" type="yes_no"/> + <property name="trueFalseBoolean" column="T_F_BOOL" type="true_false"/> + <property name="zeroOneBoolean" column="NUM_BOOL" type="boolean"/> + </class> + +</hibernate-mapping> \ No newline at end of file Added: trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/test/org/hibernate/test/hql/BooleanLiteralEntity.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -0,0 +1,45 @@ +package org.hibernate.test.hql; + +/** + * todo: describe BooleanLiteralEntity + * + * @author Steve Ebersole + */ +public class BooleanLiteralEntity { + private Long id; + private boolean yesNoBoolean; + private boolean trueFalseBoolean; + private boolean zeroOneBoolean; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public boolean isYesNoBoolean() { + return yesNoBoolean; + } + + public void setYesNoBoolean(boolean yesNoBoolean) { + this.yesNoBoolean = yesNoBoolean; + } + + public boolean isTrueFalseBoolean() { + return trueFalseBoolean; + } + + public void setTrueFalseBoolean(boolean trueFalseBoolean) { + this.trueFalseBoolean = trueFalseBoolean; + } + + public boolean isZeroOneBoolean() { + return zeroOneBoolean; + } + + public void setZeroOneBoolean(boolean zeroOneBoolean) { + this.zeroOneBoolean = zeroOneBoolean; + } +} Modified: trunk/Hibernate3/test/org/hibernate/test/hql/BulkManipulationTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/hql/BulkManipulationTest.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/test/org/hibernate/test/hql/BulkManipulationTest.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -43,7 +43,8 @@ "hql/FooBarCopy.hbm.xml", "legacy/Multi.hbm.xml", "hql/EntityWithCrazyCompositeKey.hbm.xml", - "hql/SimpleEntityWithAssociation.hbm.xml" + "hql/SimpleEntityWithAssociation.hbm.xml", + "hql/BooleanLiteralEntity.hbm.xml" }; } @@ -112,6 +113,43 @@ } + // BOOLEAN HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public void testBooleanHandling() { + TestData data = new TestData(); + data.prepare(); + + Session s = openSession(); + Transaction t = s.beginTransaction(); + + // currently, we need the three different binds because they are different underlying types... + int count = s.createQuery( "update BooleanLiteralEntity set yesNoBoolean = :b1, trueFalseBoolean = :b2, zeroOneBoolean = :b3" ) + .setBoolean( "b1", true ) + .setBoolean( "b2", true ) + .setBoolean( "b3", true ) + .executeUpdate(); + assertEquals( 1, count ); + BooleanLiteralEntity entity = ( BooleanLiteralEntity ) s.createQuery( "from BooleanLiteralEntity" ).uniqueResult(); + assertTrue( entity.isYesNoBoolean() ); + assertTrue( entity.isTrueFalseBoolean() ); + assertTrue( entity.isZeroOneBoolean() ); + s.clear(); + + count = s.createQuery( "update BooleanLiteralEntity set yesNoBoolean = true, trueFalseBoolean = true, zeroOneBoolean = true" ) + .executeUpdate(); + assertEquals( 1, count ); + entity = ( BooleanLiteralEntity ) s.createQuery( "from BooleanLiteralEntity" ).uniqueResult(); + assertTrue( entity.isYesNoBoolean() ); + assertTrue( entity.isTrueFalseBoolean() ); + assertTrue( entity.isZeroOneBoolean() ); + + t.commit(); + s.close(); + + data.cleanup(); + } + + // INSERTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public void testSimpleInsert() { @@ -411,6 +449,14 @@ // UPDATES ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + public void testIncorrectSyntax() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + s.createQuery( "update Human set Human.description = 'xyz' where Human.id = 1 and Human.description is null" ).executeUpdate(); + t.commit(); + s.close(); + } + public void testUpdateWithWhereExistsSubquery() { // multi-table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Session s = openSession(); @@ -1130,6 +1176,9 @@ pickup.setOwner( "Cecelia" ); s.save( pickup ); + BooleanLiteralEntity bool = new BooleanLiteralEntity(); + s.save( bool ); + txn.commit(); s.close(); } @@ -1144,6 +1193,7 @@ s.createQuery( "delete from Zoo" ).executeUpdate(); s.createQuery( "delete from Joiner" ).executeUpdate(); s.createQuery( "delete from Vehicle" ).executeUpdate(); + s.createQuery( "delete from BooleanLiteralEntity" ).executeUpdate(); txn.commit(); s.close(); Modified: trunk/Hibernate3/test/org/hibernate/test/hql/FooBarCopy.hbm.xml =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/hql/FooBarCopy.hbm.xml 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/test/org/hibernate/test/hql/FooBarCopy.hbm.xml 2006-06-28 02:53:39 UTC (rev 10060) @@ -118,6 +118,20 @@ </subclass> </class> + <class name="One" table="one"> + <id name="key" column="one_key"> + <generator class="native" /> + </id> + <property name="x"/> + <property column="one_value" name="value"/> + </class> + <class name="Many" table="many"> + <id name="key" column="many_key"> + <generator class="native" /> + </id> + <property name="x"/> + </class> + </hibernate-mapping> Modified: trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/test/org/hibernate/test/hql/HQLTest.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -54,6 +54,11 @@ //FAILING TESTS: + public void testManyToAnyReferences() { + assertTranslation( "from PropertySet p where p.someSpecificProperty.id is not null" ); + assertTranslation( "from PropertySet p join p.generalProperties gp where gp.id is not null" ); + } + public void testJoinFetchCollectionOfValues() { assertTranslation( "select h from Human as h join fetch h.nickNames" ); } Modified: trunk/Hibernate3/test/org/hibernate/test/hql/QueryTranslatorTestCase.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/hql/QueryTranslatorTestCase.java 2006-06-28 02:37:56 UTC (rev 10059) +++ trunk/Hibernate3/test/org/hibernate/test/hql/QueryTranslatorTestCase.java 2006-06-28 02:53:39 UTC (rev 10060) @@ -495,40 +495,41 @@ } protected String[] getMappings() { - return new String[]{ - "hql/Animal.hbm.xml", - "hql/EntityWithCrazyCompositeKey.hbm.xml", - "batchfetch/ProductLine.hbm.xml", - "cid/Customer.hbm.xml", - "cid/Order.hbm.xml", - "cid/LineItem.hbm.xml", - "cid/Product.hbm.xml", - "legacy/Baz.hbm.xml", - "legacy/Category.hbm.xml", - "legacy/Commento.hbm.xml", - "legacy/Container.hbm.xml", - "legacy/Custom.hbm.xml", - "legacy/Eye.hbm.xml", - "legacy/Fee.hbm.xml", - "legacy/FooBar.hbm.xml", - "legacy/Fum.hbm.xml", - "legacy/Glarch.hbm.xml", - "legacy/Holder.hbm.xml", - "legacy/Many.hbm.xml", - "legacy/Marelo.hbm.xml", - "legacy/MasterDetail.hbm.xml", - "legacy/Middle.hbm.xml", - "legacy/Multi.hbm.xml", - "legacy/Nameable.hbm.xml", - "legacy/One.hbm.xml", - "legacy/Qux.hbm.xml", - "legacy/Simple.hbm.xml", - "legacy/SingleSeveral.hbm.xml", - "legacy/WZ.hbm.xml", - "legacy/UpDown.hbm.xml", - "compositeelement/Parent.hbm.xml", - "onetoone/joined/Person.hbm.xml", - "hql/CrazyIdFieldNames.hbm.xml" + return new String[] { + "hql/Animal.hbm.xml", + "hql/EntityWithCrazyCompositeKey.hbm.xml", + "batchfetch/ProductLine.hbm.xml", + "cid/Customer.hbm.xml", + "cid/Order.hbm.xml", + "cid/LineItem.hbm.xml", + "cid/Product.hbm.xml", + "legacy/Baz.hbm.xml", + "legacy/Category.hbm.xml", + "legacy/Commento.hbm.xml", + "legacy/Container.hbm.xml", + "legacy/Custom.hbm.xml", + "legacy/Eye.hbm.xml", + "legacy/Fee.hbm.xml", + "legacy/FooBar.hbm.xml", + "legacy/Fum.hbm.xml", + "legacy/Glarch.hbm.xml", + "legacy/Holder.hbm.xml", + "legacy/Many.hbm.xml", + "legacy/Marelo.hbm.xml", + "legacy/MasterDetail.hbm.xml", + "legacy/Middle.hbm.xml", + "legacy/Multi.hbm.xml", + "legacy/Nameable.hbm.xml", + "legacy/One.hbm.xml", + "legacy/Qux.hbm.xml", + "legacy/Simple.hbm.xml", + "legacy/SingleSeveral.hbm.xml", + "legacy/WZ.hbm.xml", + "legacy/UpDown.hbm.xml", + "compositeelement/Parent.hbm.xml", + "onetoone/joined/Person.hbm.xml", + "hql/CrazyIdFieldNames.hbm.xml", + "any/Properties.hbm.xml" }; } |
From: <hib...@li...> - 2006-06-28 02:38:13
|
Author: ste...@jb... Date: 2006-06-27 22:37:56 -0400 (Tue, 27 Jun 2006) New Revision: 10059 Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/IdentNode.java Log: HHH-1746 : illegal property qualification causes NPE (HQL) Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/IdentNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/IdentNode.java 2006-06-27 21:25:01 UTC (rev 10058) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/IdentNode.java 2006-06-28 02:37:56 UTC (rev 10059) @@ -192,6 +192,9 @@ } Type componentType = getNakedPropertyType(fromElement); + if ( componentType == null ) { + throw new QueryException( "Unable to resolve path [" + parent.getPath() + "], unexpected token [" + getOriginalText() + "]" ); + } if (!componentType.isComponentType()) { throw new QueryException("Property '" + getOriginalText() + "' is not a component. Use an alias to reference associations or collections."); } |
From: <hib...@li...> - 2006-06-27 21:25:05
|
Author: ste...@jb... Date: 2006-06-27 17:25:01 -0400 (Tue, 27 Jun 2006) New Revision: 10058 Added: trunk/Hibernate3/test/org/hibernate/test/any/ trunk/Hibernate3/test/org/hibernate/test/any/IntegerPropertyValue.java trunk/Hibernate3/test/org/hibernate/test/any/Properties.hbm.xml trunk/Hibernate3/test/org/hibernate/test/any/PropertySet.java trunk/Hibernate3/test/org/hibernate/test/any/PropertyValue.java trunk/Hibernate3/test/org/hibernate/test/any/StringPropertyValue.java Log: <any/> and <many-to-any/> mappings useful for testing Added: trunk/Hibernate3/test/org/hibernate/test/any/IntegerPropertyValue.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/any/IntegerPropertyValue.java 2006-06-27 21:22:42 UTC (rev 10057) +++ trunk/Hibernate3/test/org/hibernate/test/any/IntegerPropertyValue.java 2006-06-27 21:25:01 UTC (rev 10058) @@ -0,0 +1,38 @@ +package org.hibernate.test.any; + +/** + * todo: describe IntegerPropertyValue + * + * @author Steve Ebersole + */ +public class IntegerPropertyValue implements PropertyValue { + private Long id; + private int value; + + public IntegerPropertyValue() { + } + + public IntegerPropertyValue(int value) { + this.value = value; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } + + public String asString() { + return Integer.toString( value ); + } +} Added: trunk/Hibernate3/test/org/hibernate/test/any/Properties.hbm.xml =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/any/Properties.hbm.xml 2006-06-27 21:22:42 UTC (rev 10057) +++ trunk/Hibernate3/test/org/hibernate/test/any/Properties.hbm.xml 2006-06-27 21:25:01 UTC (rev 10058) @@ -0,0 +1,45 @@ +<?xml version="1.0"?> +<!DOCTYPE hibernate-mapping PUBLIC + "-//Hibernate/Hibernate Mapping DTD 3.0//EN" + "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> + +<hibernate-mapping package="org.hibernate.test.any"> + + <class name="PropertySet" table="T_PROP_SET"> + <id name="id" column="ID" type="long"> + <generator class="increment"/> + </id> + <property name="name" column="NAME" type="string"/> + <any name="someSpecificProperty" id-type="long" meta-type="string" cascade="all"> + <meta-value value="I" class="IntegerPropertyValue"/> + <meta-value value="S" class="StringPropertyValue"/> + <column name="S_S_PROP_TYPE"/> + <column name="S_S_PROP_ID"/> + </any> + <map name="generalProperties" table="T_GEN_PROPS" lazy="true" cascade="all"> + <key column="PROP_SET_ID"/> + <map-key type="string" column="GEN_PROP_NAME"/> + <many-to-any id-type="long" meta-type="string"> + <meta-value value="I" class="IntegerPropertyValue"/> + <meta-value value="S" class="StringPropertyValue"/> + <column name="PROP_TYPE"/> + <column name="PROP_ID"/> + </many-to-any> + </map> + </class> + + <class name="StringPropertyValue" table="T_CHAR_PROP"> + <id name="id" column="ID" type="long"> + <generator class="increment"/> + </id> + <property name="value" column="VAL" not-null="true" type="string"/> + </class> + + <class name="IntegerPropertyValue" table="T_NUM_PROP"> + <id name="id" column="ID" type="long"> + <generator class="increment"/> + </id> + <property name="value" column="VAL" not-null="true" type="integer"/> + </class> + +</hibernate-mapping> \ No newline at end of file Added: trunk/Hibernate3/test/org/hibernate/test/any/PropertySet.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/any/PropertySet.java 2006-06-27 21:22:42 UTC (rev 10057) +++ trunk/Hibernate3/test/org/hibernate/test/any/PropertySet.java 2006-06-27 21:25:01 UTC (rev 10058) @@ -0,0 +1,55 @@ +package org.hibernate.test.any; + +import java.util.Map; +import java.util.HashMap; + +/** + * todo: describe PropertySet + * + * @author Steve Ebersole + */ +public class PropertySet { + private Long id; + private String name; + private PropertyValue someSpecificProperty; + private Map generalProperties = new HashMap(); + + public PropertySet() { + } + + public PropertySet(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public PropertyValue getSomeSpecificProperty() { + return someSpecificProperty; + } + + public void setSomeSpecificProperty(PropertyValue someSpecificProperty) { + this.someSpecificProperty = someSpecificProperty; + } + + public Map getGeneralProperties() { + return generalProperties; + } + + public void setGeneralProperties(Map generalProperties) { + this.generalProperties = generalProperties; + } +} Added: trunk/Hibernate3/test/org/hibernate/test/any/PropertyValue.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/any/PropertyValue.java 2006-06-27 21:22:42 UTC (rev 10057) +++ trunk/Hibernate3/test/org/hibernate/test/any/PropertyValue.java 2006-06-27 21:25:01 UTC (rev 10058) @@ -0,0 +1,10 @@ +package org.hibernate.test.any; + +/** + * todo: describe PropertyValue + * + * @author Steve Ebersole + */ +public interface PropertyValue { + public String asString(); +} Added: trunk/Hibernate3/test/org/hibernate/test/any/StringPropertyValue.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/any/StringPropertyValue.java 2006-06-27 21:22:42 UTC (rev 10057) +++ trunk/Hibernate3/test/org/hibernate/test/any/StringPropertyValue.java 2006-06-27 21:25:01 UTC (rev 10058) @@ -0,0 +1,38 @@ +package org.hibernate.test.any; + +/** + * todo: describe StringPropertyValue + * + * @author Steve Ebersole + */ +public class StringPropertyValue implements PropertyValue { + private Long id; + private String value; + + public StringPropertyValue() { + } + + public StringPropertyValue(String value) { + this.value = value; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + public String asString() { + return value; + } +} |
From: <hib...@li...> - 2006-06-27 21:23:31
|
Author: ste...@jb... Date: 2006-06-27 17:22:42 -0400 (Tue, 27 Jun 2006) New Revision: 10057 Modified: trunk/Hibernate3/src/org/hibernate/engine/Cascade.java trunk/Hibernate3/src/org/hibernate/engine/CascadingAction.java trunk/Hibernate3/src/org/hibernate/engine/ForeignKeys.java Log: HHH-1822 : persist() and transient, non-cascaded associations Modified: trunk/Hibernate3/src/org/hibernate/engine/Cascade.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/engine/Cascade.java 2006-06-27 21:20:52 UTC (rev 10056) +++ trunk/Hibernate3/src/org/hibernate/engine/Cascade.java 2006-06-27 21:22:42 UTC (rev 10057) @@ -232,7 +232,7 @@ final Object anything) throws HibernateException { - if ( persister.hasCascades() ) { // performance opt + if ( persister.hasCascades() || action.requiresNoCascadeChecking() ) { // performance opt if ( log.isTraceEnabled() ) { log.trace( "processing cascade " + action + " for: " + persister.getEntityName() ); } @@ -253,6 +253,15 @@ false ); } + else { + action.noCascade( + eventSource, + persister.getPropertyValue( parent, i, eventSource.getEntityMode() ), + parent, + persister, + i + ); + } } if ( log.isTraceEnabled() ) { Modified: trunk/Hibernate3/src/org/hibernate/engine/CascadingAction.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/engine/CascadingAction.java 2006-06-27 21:20:52 UTC (rev 10056) +++ trunk/Hibernate3/src/org/hibernate/engine/CascadingAction.java 2006-06-27 21:22:42 UTC (rev 10057) @@ -10,9 +10,13 @@ import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.ReplicationMode; +import org.hibernate.TransientObjectException; +import org.hibernate.persister.entity.EntityPersister; import org.hibernate.collection.PersistentCollection; import org.hibernate.event.EventSource; import org.hibernate.type.CollectionType; +import org.hibernate.type.Type; +import org.hibernate.type.EntityType; /** * A session action that may be cascaded from parent entity to its children @@ -20,13 +24,13 @@ * @author Gavin King */ public abstract class CascadingAction { - + private static final Log log = LogFactory.getLog(CascadingAction.class); /** * cascade the action to the child object */ - public abstract void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) + public abstract void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException; /** * Should this action be cascaded to the given (possibly uninitialized) collection? @@ -41,7 +45,7 @@ * @see org.hibernate.Session#delete(Object) */ public static final CascadingAction DELETE = new CascadingAction() { - public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) + public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException { if ( log.isTraceEnabled() ) { log.trace("cascading to delete: " + entityName); @@ -60,14 +64,16 @@ return "ACTION_DELETE"; } }; - + /** * @see org.hibernate.Session#lock(Object, LockMode) */ public static final CascadingAction LOCK = new CascadingAction() { - public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) + public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException { - if ( log.isTraceEnabled() ) log.trace("cascading to lock: " + entityName); + if ( log.isTraceEnabled() ) { + log.trace( "cascading to lock: " + entityName ); + } session.lock( entityName, child, LockMode.NONE/*(LockMode) anything*/ ); } public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) { @@ -82,14 +88,16 @@ return "ACTION_LOCK"; } }; - + /** * @see org.hibernate.Session#refresh(Object) */ public static final CascadingAction REFRESH = new CascadingAction() { - public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) + public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException { - if ( log.isTraceEnabled() ) log.trace("cascading to refresh: " + entityName); + if ( log.isTraceEnabled() ) { + log.trace( "cascading to refresh: " + entityName ); + } session.refresh( child, (Map) anything ); } public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) { @@ -103,14 +111,16 @@ return "ACTION_REFRESH"; } }; - + /** * @see org.hibernate.Session#evict(Object) */ public static final CascadingAction EVICT = new CascadingAction() { - public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) + public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException { - if ( log.isTraceEnabled() ) log.trace("cascading to evict: " + entityName); + if ( log.isTraceEnabled() ) { + log.trace( "cascading to evict: " + entityName ); + } session.evict(child); } public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) { @@ -124,14 +134,16 @@ return "ACTION_EVICT"; } }; - + /** * @see org.hibernate.Session#saveOrUpdate(Object) */ public static final CascadingAction SAVE_UPDATE = new CascadingAction() { - public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) + public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException { - if ( log.isTraceEnabled() ) log.trace("cascading to saveOrUpdate: " + entityName); + if ( log.isTraceEnabled() ) { + log.trace( "cascading to saveOrUpdate: " + entityName ); + } session.saveOrUpdate(entityName, child); } public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) { @@ -146,14 +158,16 @@ return "ACTION_SAVE_UPDATE"; } }; - + /** * @see org.hibernate.Session#merge(Object) */ public static final CascadingAction MERGE = new CascadingAction() { - public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) + public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException { - if ( log.isTraceEnabled() ) log.trace("cascading to merge: " + entityName); + if ( log.isTraceEnabled() ) { + log.trace( "cascading to merge: " + entityName ); + } session.merge( entityName, child, (Map) anything ); } public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) { @@ -169,15 +183,17 @@ return "ACTION_MERGE"; } }; - + /** * @see org.hibernate.classic.Session#saveOrUpdateCopy(Object) */ public static final CascadingAction SAVE_UPDATE_COPY = new CascadingAction() { // for deprecated saveOrUpdateCopy() - public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) + public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException { - if ( log.isTraceEnabled() ) log.trace("cascading to saveOrUpdateCopy: " + entityName); + if ( log.isTraceEnabled() ) { + log.trace( "cascading to saveOrUpdateCopy: " + entityName ); + } session.saveOrUpdateCopy( entityName, child, (Map) anything ); } public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) { @@ -192,14 +208,16 @@ return "ACTION_SAVE_UPDATE_COPY"; } }; - + /** * @see org.hibernate.Session#persist(Object) */ public static final CascadingAction PERSIST = new CascadingAction() { - public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) + public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException { - if ( log.isTraceEnabled() ) log.trace("cascading to persist: " + entityName); + if ( log.isTraceEnabled() ) { + log.trace( "cascading to persist: " + entityName ); + } session.persist( entityName, child, (Map) anything ); } public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) { @@ -222,7 +240,9 @@ public static final CascadingAction PERSIST_ON_FLUSH = new CascadingAction() { public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException { - if ( log.isTraceEnabled() ) log.trace("cascading to persistOnFlush: " + entityName); + if ( log.isTraceEnabled() ) { + log.trace( "cascading to persistOnFlush: " + entityName ); + } session.persistOnFlush( entityName, child, (Map) anything ); } public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) { @@ -232,18 +252,48 @@ public boolean deleteOrphans() { return true; } + public boolean requiresNoCascadeChecking() { + return true; + } + public void noCascade( + EventSource session, + Object child, + Object parent, + EntityPersister persister, + int propertyIndex) { + if ( child == null ) { + return; + } + Type type = persister.getPropertyTypes()[propertyIndex]; + if ( type.isEntityType() ) { + String childEntityName = ( ( EntityType ) type ).getAssociatedEntityName( session.getFactory() ); + if ( ForeignKeys.isTransient( childEntityName, child, null, session ) ) { + String parentEntiytName = persister.getEntityName(); + String propertyName = persister.getPropertyNames()[propertyIndex]; + throw new TransientObjectException( + "object references an unsaved transient instance - " + + "save the transient instance before flushing: " + + parentEntiytName + "." + propertyName + " -> " + childEntityName + ); + + } + } + } + public String toString() { return "ACTION_PERSIST_ON_FLUSH"; } }; - + /** * @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode) */ public static final CascadingAction REPLICATE = new CascadingAction() { - public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) + public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled) throws HibernateException { - if ( log.isTraceEnabled() ) log.trace("cascading to replicate: " + entityName); + if ( log.isTraceEnabled() ) { + log.trace( "cascading to replicate: " + entityName ); + } session.replicate( entityName, child, (ReplicationMode) anything ); } public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) { @@ -257,9 +307,17 @@ return "ACTION_REPLICATE"; } }; - + CascadingAction() {} + public boolean requiresNoCascadeChecking() { + return false; + } + + + public void noCascade(EventSource session, Object child, Object parent, EntityPersister persister, int propertyIndex) { + } + /** * Iterate all the collection elements, loading them from the database if necessary. */ @@ -281,7 +339,7 @@ return ( (PersistentCollection) collection ).queuedAdditionIterator(); } } - + private static boolean collectionIsInitialized(Object collection) { return !(collection instanceof PersistentCollection) || ( (PersistentCollection) collection ).wasInitialized(); } Modified: trunk/Hibernate3/src/org/hibernate/engine/ForeignKeys.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/engine/ForeignKeys.java 2006-06-27 21:20:52 UTC (rev 10056) +++ trunk/Hibernate3/src/org/hibernate/engine/ForeignKeys.java 2006-06-27 21:22:42 UTC (rev 10057) @@ -215,7 +215,7 @@ // context-entity-identifier returns null explicitly if the entity // is not associated with the persistence context; so make some // deeper checks... - if ( isTransient(entityName, object, null, session) ) { + if ( isTransient(entityName, object, Boolean.FALSE, session) ) { throw new TransientObjectException( "object references an unsaved transient instance - save the transient instance before flushing: " + entityName == null ? session.guessEntityName( object ) : entityName |
From: <hib...@li...> - 2006-06-27 21:21:28
|
Author: ste...@jb... Date: 2006-06-27 17:20:52 -0400 (Tue, 27 Jun 2006) New Revision: 10056 Added: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildInfo.java trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentInfo.java Modified: trunk/Hibernate3/test/org/hibernate/test/jpa/AbstractJPATest.java trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/CascadeTest.java Log: full tests for HHH-1822 (missed some) Modified: trunk/Hibernate3/test/org/hibernate/test/jpa/AbstractJPATest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/AbstractJPATest.java 2006-06-27 21:17:04 UTC (rev 10055) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/AbstractJPATest.java 2006-06-27 21:20:52 UTC (rev 10056) @@ -4,6 +4,16 @@ import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.proxy.EntityNotFoundDelegate; +import org.hibernate.event.def.DefaultPersistEventListener; +import org.hibernate.event.def.DefaultAutoFlushEventListener; +import org.hibernate.event.def.DefaultFlushEventListener; +import org.hibernate.event.def.DefaultFlushEntityEventListener; +import org.hibernate.event.AutoFlushEventListener; +import org.hibernate.event.FlushEventListener; +import org.hibernate.event.PersistEventListener; +import org.hibernate.event.FlushEntityEventListener; +import org.hibernate.engine.CascadingAction; +import org.hibernate.util.IdentityMap; import java.io.Serializable; @@ -26,6 +36,11 @@ cfg.setProperty( Environment.JPAQL_STRICT_COMPLIANCE, "true" ); cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "false" ); cfg.setEntityNotFoundDelegate( new JPAEntityNotFoundDelegate() ); + cfg.getEventListeners().setPersistEventListeners( buildPersistEventListeners() ); + cfg.getEventListeners().setPersistOnFlushEventListeners( buildPersisOnFlushEventListeners() ); + cfg.getEventListeners().setAutoFlushEventListeners( buildAutoFlushEventListeners() ); + cfg.getEventListeners().setFlushEventListeners( buildFlushEventListeners() ); + cfg.getEventListeners().setFlushEntityEventListeners( buildFlushEntityEventListeners() ); } public String getCacheConcurrencyStrategy() { @@ -33,6 +48,9 @@ return null; } + + // mimic specific exception aspects of the JPA environment ~~~~~~~~~~~~~~~~ + private static class JPAEntityNotFoundDelegate implements EntityNotFoundDelegate { public void handleEntityNotFound(String entityName, Serializable id) { throw new EntityNotFoundException( entityName, id ); @@ -64,4 +82,67 @@ return id; } } + + + // mimic specific event aspects of the JPA environment ~~~~~~~~~~~~~~~~~~~~ + + protected PersistEventListener[] buildPersistEventListeners() { + return new PersistEventListener[] { new JPAPersistEventListener() }; + } + + protected PersistEventListener[] buildPersisOnFlushEventListeners() { + return new PersistEventListener[] { new JPAPersistOnFlushEventListener() }; + } + + protected AutoFlushEventListener[] buildAutoFlushEventListeners() { + return new AutoFlushEventListener[] { JPAAutoFlushEventListener.INSTANCE }; + } + + protected FlushEventListener[] buildFlushEventListeners() { + return new FlushEventListener[] { JPAFlushEventListener.INSTANCE }; + } + + protected FlushEntityEventListener[] buildFlushEntityEventListeners() { + return new FlushEntityEventListener[] { new JPAFlushEntityEventListener() }; + } + + public static class JPAPersistEventListener extends DefaultPersistEventListener { + // overridden in JPA impl for entity callbacks... + } + + public static class JPAPersistOnFlushEventListener extends JPAPersistEventListener { + protected CascadingAction getCascadeAction() { + return CascadingAction.PERSIST_ON_FLUSH; + } + } + + public static class JPAAutoFlushEventListener extends DefaultAutoFlushEventListener { + // not sure why EM code has this ... + public static final AutoFlushEventListener INSTANCE = new JPAAutoFlushEventListener(); + + protected CascadingAction getCascadingAction() { + return CascadingAction.PERSIST_ON_FLUSH; + } + + protected Object getAnything() { + return IdentityMap.instantiate( 10 ); + } + } + + public static class JPAFlushEventListener extends DefaultFlushEventListener { + // not sure why EM code has this ... + public static final FlushEventListener INSTANCE = new JPAFlushEventListener(); + + protected CascadingAction getCascadingAction() { + return CascadingAction.PERSIST_ON_FLUSH; + } + + protected Object getAnything() { + return IdentityMap.instantiate( 10 ); + } + } + + public static class JPAFlushEntityEventListener extends DefaultFlushEntityEventListener { + // in JPA, used mainly for preUpdate callbacks... + } } Modified: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/CascadeTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/CascadeTest.java 2006-06-27 21:17:04 UTC (rev 10055) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/CascadeTest.java 2006-06-27 21:20:52 UTC (rev 10056) @@ -317,24 +317,4 @@ } } } - - protected FlushEntityEventListener[] buildFlushEntityEventListeners() { - return new FlushEntityEventListener[] { new JPACheckingFlushEntityEventListener() }; - } - - public static class JPACheckingFlushEntityEventListener extends JPAFlushEntityEventListener { - public void onFlushEntity(FlushEntityEvent event) throws HibernateException { - super.onFlushEntity( event ); //To change body of overridden methods use File | Settings | File Templates. - } - - protected void validate(Object entity, EntityPersister persister, Status status, EntityMode entityMode) { - super.validate( entity, persister, status, entityMode ); - } - } - - public static class JPAPersistTransientAssociationChecker { - // implements the checks required by the JPA spec regarding entities with - // non-cacaded associations to transient entities. - - } } Added: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildInfo.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildInfo.java 2006-06-27 21:17:04 UTC (rev 10055) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildInfo.java 2006-06-27 21:20:52 UTC (rev 10056) @@ -0,0 +1,39 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe ChildInfo + * + * @author Steve Ebersole + */ +public class ChildInfo { + private Long id; + private Child owner; + private String info; + + public ChildInfo() { + } + + public ChildInfo(String info) { + this.info = info; + } + + public Long getId() { + return id; + } + + public Child getOwner() { + return owner; + } + + public void setOwner(Child owner) { + this.owner = owner; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} Added: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java 2006-06-27 21:17:04 UTC (rev 10055) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildInfoAssigned.java 2006-06-27 21:20:52 UTC (rev 10056) @@ -0,0 +1,40 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe ChildInfo + * + * @author Steve Ebersole + */ +public class ChildInfoAssigned { + private Long id; + private ChildAssigned owner; + private String info; + + public ChildInfoAssigned() { + } + + public ChildInfoAssigned(Long id, String info) { + this.id = id; + this.info = info; + } + + public Long getId() { + return id; + } + + public ChildAssigned getOwner() { + return owner; + } + + public void setOwner(ChildAssigned owner) { + this.owner = owner; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} Added: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentInfo.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentInfo.java 2006-06-27 21:17:04 UTC (rev 10055) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentInfo.java 2006-06-27 21:20:52 UTC (rev 10056) @@ -0,0 +1,39 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe ChildInfo + * + * @author Steve Ebersole + */ +public class ParentInfo { + private Long id; + private Parent owner; + private String info; + + public ParentInfo() { + } + + public ParentInfo(String info) { + this.info = info; + } + + public Long getId() { + return id; + } + + public Parent getOwner() { + return owner; + } + + public void setOwner(Parent owner) { + this.owner = owner; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} |
From: <hib...@li...> - 2006-06-27 21:18:39
|
Author: ste...@jb... Date: 2006-06-27 17:17:04 -0400 (Tue, 27 Jun 2006) New Revision: 10055 Added: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Other.java trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/OtherAssigned.java trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java Modified: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/CascadeTest.java trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Child.java trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildAssigned.java trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Parent.java trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentAssigned.java trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml Log: full tests for HHH-1822 Modified: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/CascadeTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/CascadeTest.java 2006-06-27 21:12:17 UTC (rev 10054) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/CascadeTest.java 2006-06-27 21:17:04 UTC (rev 10055) @@ -3,13 +3,26 @@ import org.hibernate.test.jpa.AbstractJPATest; import org.hibernate.Session; import org.hibernate.TransientObjectException; -import org.hibernate.event.def.DefaultPersistOnFlushEventListener; +import org.hibernate.EntityMode; +import org.hibernate.HibernateException; +import org.hibernate.engine.Status; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.event.FlushEntityEventListener; +import org.hibernate.event.FlushEntityEvent; import org.hibernate.cfg.Configuration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** - * todo: describe CascadeTest + * According to the JPA spec, persist()ing an entity should throw an exception + * when said entity contains a reference to a transient entity through a mapped + * association where that association is not marked for cascading the persist + * operation. + * <p/> + * This test-case tests that requirement in the various association style + * scenarios such as many-to-one, one-to-one, many-to-one (property-ref), + * one-to-one (property-ref). Additionally, it performs each of these tests + * in both generated and assigned identifier usages... * * @author Steve Ebersole */ @@ -27,59 +40,301 @@ protected void configure(Configuration cfg) { super.configure( cfg ); -// cfg.setListeners( "create", new DefaultPersistOnFlushEventListener[] { new DefaultPersistOnFlushEventListener() } ); -// cfg.setListeners( "create-onflush", new DefaultPersistOnFlushEventListener[] { new DefaultPersistOnFlushEventListener() } ); } - public void testPersistOnFlushWithNoCascadeToTransientAssociation() { - // according to the JPA spec, persist()ing an entity should throw - // an exception when said entity contains a reference to a transient - // asoociation where that association is not marked for cascading - // the persist operation... - Session s = openSession(); - s.beginTransaction(); - Parent p = new Parent( "p1" ); - Child c = new Child( "c1" ); - c.setParent( p ); - s.persist( c ); + public void testManyToOneGeneratedIdsOnSave() { + // NOTES: Child defines a many-to-one back to its Parent. This + // association does not define persist cascading (which is natural; + // a child should not be able to create its parent). try { + Session s = openSession(); + s.beginTransaction(); + Parent p = new Parent( "parent" ); + Child c = new Child( "child" ); + c.setParent( p ); + s.save( c ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testManyToOneGeneratedIds() { + // NOTES: Child defines a many-to-one back to its Parent. This + // association does not define persist cascading (which is natural; + // a child should not be able to create its parent). + try { + Session s = openSession(); + s.beginTransaction(); + Parent p = new Parent( "parent" ); + Child c = new Child( "child" ); + c.setParent( p ); + s.persist( c ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testManyToOneAssignedIds() { + // NOTES: Child defines a many-to-one back to its Parent. This + // association does not define persist cascading (which is natural; + // a child should not be able to create its parent). + try { + Session s = openSession(); + s.beginTransaction(); + ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" ); + ChildAssigned c = new ChildAssigned( new Long( 2 ), "child" ); + c.setParent( p ); + s.persist( c ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testOneToOneGeneratedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + Parent p = new Parent( "parent" ); + ParentInfo info = new ParentInfo( "xyz" ); + p.setInfo( info ); + info.setOwner( p ); + s.persist( p ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testOneToOneAssignedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" ); + ParentInfoAssigned info = new ParentInfoAssigned( "something secret" ); + p.setInfo( info ); + info.setOwner( p ); + s.persist( p ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testManyToOnePropertyRefGeneratedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + Parent p = new Parent( "parent" ); + Other other = new Other(); + other.setOwner( p ); + s.persist( other ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testManyToOnePropertyRefAssignedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + ParentAssigned p = new ParentAssigned( new Long( 1 ), "parent" ); + OtherAssigned other = new OtherAssigned( new Long( 2 ) ); + other.setOwner( p ); + s.persist( other ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception", e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testOneToOnePropertyRefGeneratedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + Child c2 = new Child( "c2" ); + ChildInfo info = new ChildInfo( "blah blah blah" ); + c2.setInfo( info ); + info.setOwner( c2 ); + s.persist( c2 ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception : " + e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + public void testOneToOnePropertyRefAssignedIds() { + try { + Session s = openSession(); + s.beginTransaction(); + ChildAssigned c2 = new ChildAssigned( new Long( 3 ), "c3" ); + ChildInfoAssigned info = new ChildInfoAssigned( new Long( 4 ), "blah blah blah" ); + c2.setInfo( info ); + info.setOwner( c2 ); + s.persist( c2 ); + try { + s.getTransaction().commit(); + fail( "expecting TransientObjectException on flush" ); + } + catch( TransientObjectException e ) { + // expected result + log.trace( "handled expected exception : " + e ); + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + finally { + cleanupData(); + } + } + + + private void cleanupData() { + Session s = null; + try { + s = openSession(); + s.beginTransaction(); + s.createQuery( "delete ChildInfoAssigned" ).executeUpdate(); + s.createQuery( "delete ChildAssigned" ).executeUpdate(); + s.createQuery( "delete ParentAssigned" ).executeUpdate(); + s.createQuery( "delete ChildInfoAssigned" ).executeUpdate(); + s.createQuery( "delete ChildAssigned" ).executeUpdate(); + s.createQuery( "delete ParentAssigned" ).executeUpdate(); s.getTransaction().commit(); - fail( "expecting TransientObjectException on flush" ); } - catch( TransientObjectException e ) { - // expected result - log.trace( "handled expected exception", e ); + catch( Throwable t ) { + log.warn( "unable to cleanup test data [" + fullTestName() + "] : " + t ); } - s.close(); + finally { + if ( s != null ) { + try { + s.close(); + } + catch( Throwable ignore ) { + } + } + } + } - s = openSession(); - s.beginTransaction(); - s.createQuery( "delete Child" ).executeUpdate(); - s.createQuery( "delete Parent" ).executeUpdate(); - s.getTransaction().commit(); - s.close(); + protected FlushEntityEventListener[] buildFlushEntityEventListeners() { + return new FlushEntityEventListener[] { new JPACheckingFlushEntityEventListener() }; } - public void testPersistOnFlushWithNoCascadeToTransientAssociationWithAssignedIdentifier() { - // according to the JPA spec, persist()ing an entity should throw - // an exception when said entity contains a reference to a transient - // asoociation where that association is not marked for cascading - // the persist operation... - Session s = openSession(); - s.beginTransaction(); - ParentAssigned p = new ParentAssigned( new Long( 1 ), "p1" ); - ChildAssigned c = new ChildAssigned( new Long( 2 ), "c1" ); - c.setParent( p ); - s.persist( c ); - s.getTransaction().commit(); - s.close(); + public static class JPACheckingFlushEntityEventListener extends JPAFlushEntityEventListener { + public void onFlushEntity(FlushEntityEvent event) throws HibernateException { + super.onFlushEntity( event ); //To change body of overridden methods use File | Settings | File Templates. + } - s = openSession(); - s.beginTransaction(); - s.createQuery( "delete ChildAssigned" ).executeUpdate(); - s.createQuery( "delete ParentAssigned" ).executeUpdate(); - s.getTransaction().commit(); - s.close(); + protected void validate(Object entity, EntityPersister persister, Status status, EntityMode entityMode) { + super.validate( entity, persister, status, entityMode ); + } } + + public static class JPAPersistTransientAssociationChecker { + // implements the checks required by the JPA spec regarding entities with + // non-cacaded associations to transient entities. + + } } Modified: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Child.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Child.java 2006-06-27 21:12:17 UTC (rev 10054) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Child.java 2006-06-27 21:17:04 UTC (rev 10055) @@ -9,6 +9,7 @@ private Long id; private String name; private Parent parent; + private ChildInfo info; public Child() { } @@ -40,4 +41,12 @@ public void setParent(Parent parent) { this.parent = parent; } + + public ChildInfo getInfo() { + return info; + } + + public void setInfo(ChildInfo info) { + this.info = info; + } } Modified: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildAssigned.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildAssigned.java 2006-06-27 21:12:17 UTC (rev 10054) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ChildAssigned.java 2006-06-27 21:17:04 UTC (rev 10055) @@ -9,6 +9,7 @@ private Long id; private String name; private ParentAssigned parent; + private ChildInfoAssigned info; public ChildAssigned() { } @@ -37,4 +38,12 @@ public void setParent(ParentAssigned parent) { this.parent = parent; } + + public ChildInfoAssigned getInfo() { + return info; + } + + public void setInfo(ChildInfoAssigned info) { + this.info = info; + } } Added: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Other.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Other.java 2006-06-27 21:12:17 UTC (rev 10054) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Other.java 2006-06-27 21:17:04 UTC (rev 10055) @@ -0,0 +1,23 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe Other + * + * @author Steve Ebersole + */ +public class Other { + private Long id; + private Parent owner; + + public Long getId() { + return id; + } + + public Parent getOwner() { + return owner; + } + + public void setOwner(Parent owner) { + this.owner = owner; + } +} Added: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/OtherAssigned.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/OtherAssigned.java 2006-06-27 21:12:17 UTC (rev 10054) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/OtherAssigned.java 2006-06-27 21:17:04 UTC (rev 10055) @@ -0,0 +1,30 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe Other + * + * @author Steve Ebersole + */ +public class OtherAssigned { + private Long id; + private ParentAssigned owner; + + public OtherAssigned() { + } + + public OtherAssigned(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public ParentAssigned getOwner() { + return owner; + } + + public void setOwner(ParentAssigned owner) { + this.owner = owner; + } +} Modified: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Parent.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Parent.java 2006-06-27 21:12:17 UTC (rev 10054) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/Parent.java 2006-06-27 21:17:04 UTC (rev 10055) @@ -8,6 +8,7 @@ public class Parent { private Long id; private String name; + private ParentInfo info; public Parent() { } @@ -31,4 +32,12 @@ public void setName(String name) { this.name = name; } + + public ParentInfo getInfo() { + return info; + } + + public void setInfo(ParentInfo info) { + this.info = info; + } } Modified: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentAssigned.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentAssigned.java 2006-06-27 21:12:17 UTC (rev 10054) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentAssigned.java 2006-06-27 21:17:04 UTC (rev 10055) @@ -8,6 +8,7 @@ public class ParentAssigned { private Long id; private String name; + private ParentInfoAssigned info; public ParentAssigned() { } @@ -28,4 +29,12 @@ public void setName(String name) { this.name = name; } + + public ParentInfoAssigned getInfo() { + return info; + } + + public void setInfo(ParentInfoAssigned info) { + this.info = info; + } } Modified: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml 2006-06-27 21:12:17 UTC (rev 10054) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentChild.hbm.xml 2006-06-27 21:17:04 UTC (rev 10055) @@ -4,34 +4,94 @@ <hibernate-mapping package="org.hibernate.test.jpa.cascade" default-access="field"> - <class name="Parent" table="PARENT"> + <!-- +++++++++++++ Generated ids ++++++++++++++++++++++ --> + + <class name="Parent" table="PARENT"> <id name="id" column="ID" type="long"> <generator class="increment"/> </id> - <property name="name"/> + <property name="name" type="string" unique="true"/> + <one-to-one name="info" class="ParentInfo" cascade="none"/> </class> <class name="Child" table="CHILD"> <id name="id" column="ID" type="long"> <generator class="increment"/> </id> - <property name="name"/> + <property name="name" type="string"/> <many-to-one name="parent" class="Parent" cascade="none"/> + <one-to-one name="info" property-ref="owner" class="ChildInfo" cascade="none"/> </class> - <class name="ParentAssigned" table="PARENT"> + <class name="ParentInfo" table="P_INFO"> <id name="id" column="ID" type="long"> + <generator class="foreign"> + <param name="property">owner</param> + </generator> + </id> + <property name="info" column="INFO" type="string"/> + <one-to-one name="owner" class="Parent" constrained="true" cascade="none"/> + </class> + + <class name="ChildInfo" table="C_INFO"> + <id name="id" column="ID" type="long"> + <generator class="increment"/> + </id> + <property name="info" column="INFO" type="string"/> + <many-to-one name="owner" class="Child" column="CHILD_ID" cascade="none"/> + </class> + + <class name="Other" table="OTHER"> + <id name="id" column="ID" type="long"> + <generator class="increment"/> + </id> + <many-to-one name="owner" column="OWNER_NAME" class="Parent" property-ref="name" cascade="none"/> + </class> + + + + <!-- +++++++++++++ Assigned ids ++++++++++++++++++++++ --> + + <class name="ParentAssigned" table="PARENT_A"> + <id name="id" column="ID" type="long"> <generator class="assigned"/> </id> - <property name="name"/> + <property name="name" type="string" unique="true"/> + <one-to-one name="info" class="ParentInfoAssigned"/> </class> - <class name="ChildAssigned" table="CHILD"> + <class name="ChildAssigned" table="CHILD_A"> <id name="id" column="ID" type="long"> <generator class="assigned"/> </id> - <property name="name"/> + <property name="name" type="string"/> <many-to-one name="parent" class="ParentAssigned" cascade="none"/> + <one-to-one name="info" property-ref="owner" class="ChildInfoAssigned" cascade="none"/> </class> + <class name="ParentInfoAssigned" table="P_INFO_A"> + <id name="id" column="ID" type="long"> + <generator class="foreign"> + <param name="property">owner</param> + </generator> + </id> + <property name="info" column="INFO" type="string"/> + <one-to-one name="owner" class="ParentAssigned" constrained="true"/> + </class> + + <class name="ChildInfoAssigned" table="C_INFO_A"> + <id name="id" column="ID" type="long"> + <generator class="assigned"/> + </id> + <property name="info" column="INFO" type="string"/> + <many-to-one name="owner" class="ChildAssigned" column="CHILD_ID" cascade="none"/> + </class> + + <class name="OtherAssigned" table="OTHER_A"> + <id name="id" column="ID" type="long"> + <generator class="assigned"/> + </id> + <many-to-one name="owner" column="OWNER_NAME" class="ParentAssigned" property-ref="name" cascade="none"/> + </class> + </hibernate-mapping> \ No newline at end of file Added: trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java 2006-06-27 21:12:17 UTC (rev 10054) +++ trunk/Hibernate3/test/org/hibernate/test/jpa/cascade/ParentInfoAssigned.java 2006-06-27 21:17:04 UTC (rev 10055) @@ -0,0 +1,39 @@ +package org.hibernate.test.jpa.cascade; + +/** + * todo: describe ChildInfo + * + * @author Steve Ebersole + */ +public class ParentInfoAssigned { + private Long id; + private ParentAssigned owner; + private String info; + + public ParentInfoAssigned() { + } + + public ParentInfoAssigned(String info) { + this.info = info; + } + + public Long getId() { + return id; + } + + public ParentAssigned getOwner() { + return owner; + } + + public void setOwner(ParentAssigned owner) { + this.owner = owner; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} |
From: <hib...@li...> - 2006-06-27 21:12:35
|
Author: ste...@jb... Date: 2006-06-27 17:12:17 -0400 (Tue, 27 Jun 2006) New Revision: 10054 Modified: trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java Log: fixed arguable test Modified: trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java 2006-06-26 23:20:32 UTC (rev 10053) +++ trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java 2006-06-27 21:12:17 UTC (rev 10054) @@ -493,6 +493,16 @@ s = openSession(); t = s.beginTransaction(); + s.delete(emp2); + + s.delete(jboss); + s.delete(gavin); + s.delete(ifa); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); Dimension dim = new Dimension( 3, Integer.MAX_VALUE ); s.save( dim ); // s.flush(); @@ -503,16 +513,6 @@ s = openSession(); t = s.beginTransaction(); - s.delete(emp2); - - s.delete(jboss); - s.delete(gavin); - s.delete(ifa); - t.commit(); - s.close(); - - s = openSession(); - t = s.beginTransaction(); SpaceShip enterprise = new SpaceShip(); enterprise.setModel( "USS" ); enterprise.setName( "Entreprise" ); @@ -524,8 +524,8 @@ Object[] result = (Object[]) s.getNamedQuery( "spaceship" ).uniqueResult(); enterprise = (SpaceShip) result[0]; assertTrue(50d == enterprise.getSpeed() ); - assertTrue( 450d == ( (BigInteger) result[1] ).doubleValue() ); - assertTrue( 4500d == ( (BigDecimal) result[2] ).doubleValue() ); + assertTrue( 450d == extractDoubleValue( result[1] ) ); + assertTrue( 4500d == extractDoubleValue( result[2] ) ); s.delete( dim ); t.commit(); s.close(); @@ -542,8 +542,18 @@ } + private double extractDoubleValue(Object value) { + if ( value instanceof BigInteger ) { + return ( ( BigInteger ) value ).doubleValue(); + } + else if ( value instanceof BigDecimal ) { + return ( ( BigDecimal ) value ).doubleValue(); + } + else { + return Double.valueOf( value.toString() ).doubleValue(); + } + } - public static Test suite() { return new TestSuite(GeneralTest.class); } |
From: <hib...@li...> - 2006-06-26 23:20:35
|
Author: epbernard Date: 2006-06-26 19:20:32 -0400 (Mon, 26 Jun 2006) New Revision: 10053 Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/MapBinder.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Version.java Log: ANN-243 use quoted columns when needed Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/MapBinder.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/MapBinder.java 2006-06-26 22:35:11 UTC (rev 10052) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/MapBinder.java 2006-06-26 23:20:32 UTC (rev 10053) @@ -324,8 +324,7 @@ Formula formula = new Formula(); String formulaString; if ( current instanceof Column ) { - formulaString = ( (Column) current ).getName(); - //FIXME support quoted name + formulaString = ( (Column) current ).getQuotedName(); } else if ( current instanceof Formula ) { formulaString = ( (Formula) current ).getFormula(); Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Version.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Version.java 2006-06-26 22:35:11 UTC (rev 10052) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/indexcoll/Version.java 2006-06-26 23:20:32 UTC (rev 10053) @@ -6,6 +6,7 @@ import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; +import javax.persistence.Column; /** * @author Emmanuel Bernard @@ -28,6 +29,7 @@ this.id = id; } + @Column(name="`code_name`") public String getCodeName() { return codeName; } |
Author: epbernard Date: 2006-06-26 18:35:11 -0400 (Mon, 26 Jun 2006) New Revision: 10052 Removed: trunk/HibernateExt/metadata/src/test/org/hibernate/test/lucene/Document.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/lucene/LuceneTest.java Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/EntityBinder.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/SportCar.java Log: tests on polymorphism and better user feedback Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/EntityBinder.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/EntityBinder.java 2006-06-26 22:23:32 UTC (rev 10051) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/cfg/annotations/EntityBinder.java 2006-06-26 22:35:11 UTC (rev 10052) @@ -63,6 +63,7 @@ private boolean isPropertyAnnotated = false; private boolean dynamicInsert; private boolean dynamicUpdate; + private boolean explicitHibernateEntityAnnotation; private boolean mutable; private OptimisticLockType optimisticLockType; private String persister; @@ -113,6 +114,7 @@ persister = hibAnn.persister(); selectBeforeUpdate = hibAnn.selectBeforeUpdate(); polymorphismType = hibAnn.polymorphism(); + explicitHibernateEntityAnnotation = true; } else { //default values when the annotation is not there @@ -164,6 +166,12 @@ rootClass.setLazyPropertiesCacheable( cacheLazyProperty ); } } + else { + if (explicitHibernateEntityAnnotation) { + log.warn("@org.hibernate.annotations.Entity used on a non root entity: ignored for " + + annotatedClass.getName() ); + } + } persistentClass.setOptimisticLockMode( getVersioning( optimisticLockType ) ); persistentClass.setSelectBeforeUpdate( selectBeforeUpdate ); if ( ! AnnotationBinder.isDefault( persister ) ) { Modified: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/SportCar.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/SportCar.java 2006-06-26 22:23:32 UTC (rev 10051) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/SportCar.java 2006-06-26 22:35:11 UTC (rev 10052) @@ -4,10 +4,13 @@ import javax.persistence.Entity; import javax.persistence.Table; +import org.hibernate.annotations.PolymorphismType; + /** * @author Emmanuel Bernard */ @Entity @Table(name = "sport_car") +...@or...notations.Entity(polymorphism = PolymorphismType.EXPLICIT) //raise a warn public class SportCar extends Car { } Deleted: trunk/HibernateExt/metadata/src/test/org/hibernate/test/lucene/Document.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/lucene/Document.java 2006-06-26 22:23:32 UTC (rev 10051) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/lucene/Document.java 2006-06-26 22:35:11 UTC (rev 10052) @@ -1,72 +0,0 @@ -//$Id$ -package org.hibernate.test.lucene; - -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; -import javax.persistence.Lob; - -import org.hibernate.lucene.Indexed; -import org.hibernate.lucene.Keyword; -import org.hibernate.lucene.Text; -import org.hibernate.lucene.Unstored; -import org.hibernate.lucene.Boost; - -@Entity -@Indexed(index = "Documents") -public class Document { - private Long id; - private String title; - private String summary; - private String text; - - Document() { - } - - public Document(String title, String summary, String text) { - super(); - this.summary = summary; - this.text = text; - this.title = title; - } - - @Id - @GeneratedValue - @Keyword(id = true) - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - @Text - @Boost(2) - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - @Unstored(name = "Abstract") - public String getSummary() { - return summary; - } - - public void setSummary(String summary) { - this.summary = summary; - } - - @Lob - @Unstored - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } -} Deleted: trunk/HibernateExt/metadata/src/test/org/hibernate/test/lucene/LuceneTest.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/lucene/LuceneTest.java 2006-06-26 22:23:32 UTC (rev 10051) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/lucene/LuceneTest.java 2006-06-26 22:35:11 UTC (rev 10052) @@ -1,195 +0,0 @@ -//$Id$ -package org.hibernate.test.lucene; - -import java.io.File; -import java.util.List; - -import junit.framework.Test; -import junit.framework.TestSuite; -import org.apache.lucene.analysis.StopAnalyzer; -import org.apache.lucene.analysis.standard.StandardAnalyzer; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.Term; -import org.apache.lucene.index.TermDocs; -import org.apache.lucene.queryParser.QueryParser; -import org.apache.lucene.search.IndexSearcher; -import org.apache.lucene.search.Hits; -import org.hibernate.Session; -import org.hibernate.cfg.Configuration; -import org.hibernate.event.PostDeleteEventListener; -import org.hibernate.event.PostInsertEventListener; -import org.hibernate.event.PostUpdateEventListener; -import org.hibernate.lucene.Environment; -import org.hibernate.lucene.event.LuceneEventListener; - -/** - * @author Gavin King - */ -public class LuceneTest extends org.hibernate.test.annotations.TestCase { - - public LuceneTest(String str) { - super( str ); - } - - @Override - protected void setUp() throws Exception { - File sub = getBaseIndexDir(); - sub.mkdir(); - super.setUp(); - } - - private File getBaseIndexDir() { - File current = new File( "." ); - File sub = new File( current, "indextemp" ); - return sub; - } - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - File sub = getBaseIndexDir(); - delete( sub ); - } - - private void delete(File sub) { - if ( sub.isDirectory() ) { - for ( File file : sub.listFiles() ) { - delete( file ); - } - sub.delete(); - } - else { - sub.delete(); - } - } - - public void testLucene() throws Exception { - - - Session s = getSessions().openSession(); - s.getTransaction().begin(); - s.persist( - new Document( "Hibernate in Action", "Object/relational mapping with Hibernate", "blah blah blah" ) - ); - s.getTransaction().commit(); - s.close(); - - IndexReader reader = IndexReader.open( new File( getBaseIndexDir(), "Documents" ) ); - try { - int num = reader.numDocs(); - assertEquals( 1, num ); - TermDocs docs = reader.termDocs( new Term( "Abstract", "Hibernate" ) ); - org.apache.lucene.document.Document doc = reader.document( docs.doc() ); - assertFalse( docs.next() ); - docs = reader.termDocs( new Term( "Title", "Action" ) ); - doc = reader.document( docs.doc() ); - assertFalse( docs.next() ); - assertEquals( "1", doc.getField( "id" ).stringValue() ); - } - finally { - reader.close(); - } - - s = getSessions().openSession(); - s.getTransaction().begin(); - Document entity = (Document) s.get( Document.class, new Long( 1 ) ); - entity.setSummary( "Object/relational mapping with EJB3" ); - s.persist( new Document( "Seam in Action", "", "blah blah blah blah" ) ); - s.getTransaction().commit(); - s.close(); - - reader = IndexReader.open( new File( getBaseIndexDir(), "Documents" ) ); - try { - int num = reader.numDocs(); - assertEquals( 2, num ); - TermDocs docs = reader.termDocs( new Term( "Abstract", "EJB3" ) ); - org.apache.lucene.document.Document doc = reader.document( docs.doc() ); - assertFalse( docs.next() ); - } - finally { - reader.close(); - } - - s = getSessions().openSession(); - s.getTransaction().begin(); - s.delete( entity ); - s.getTransaction().commit(); - s.close(); - - reader = IndexReader.open( new File( getBaseIndexDir(), "Documents" ) ); - try { - int num = reader.numDocs(); - assertEquals( 1, num ); - TermDocs docs = reader.termDocs( new Term( "Title", "Seam" ) ); - org.apache.lucene.document.Document doc = reader.document( docs.doc() ); - assertFalse( docs.next() ); - assertEquals( "2", doc.getField( "id" ).stringValue() ); - } - finally { - reader.close(); - } - - s = getSessions().openSession(); - s.getTransaction().begin(); - s.delete( s.createCriteria( Document.class ).uniqueResult() ); - s.getTransaction().commit(); - s.close(); - } - - public void testBoost() throws Exception { - - - Session s = getSessions().openSession(); - s.getTransaction().begin(); - s.persist( - new Document( "Hibernate in Action", "Object and Relational", "blah blah blah" ) - ); - s.persist( - new Document( "Object and Relational", "Hibernate in Action", "blah blah blah" ) - ); - s.getTransaction().commit(); - s.close(); - - IndexSearcher searcher = new IndexSearcher( new File( getBaseIndexDir(), "Documents" ).getCanonicalPath() ); - try { - QueryParser qp = new QueryParser("id", new StandardAnalyzer() ); - Hits hits = searcher.search( qp.parse("title:Action OR Abstract:Action") ); - assertEquals( 2, hits.length() ); - assertTrue( hits.score( 0 ) == 2*hits.score( 1 ) ); - assertEquals( "Hibernate in Action", hits.doc(0).get( "title") ); - } - finally { - if (searcher != null) searcher.close(); - } - - - s = getSessions().openSession(); - s.getTransaction().begin(); - List list = s.createQuery( "from Document" ).list(); - for (Document document : (List<Document>) list) { - s.delete( document ); - } - s.getTransaction().commit(); - s.close(); - } - - protected Class[] getMappings() { - return new Class[]{Document.class}; - } - - public static Test suite() { - return new TestSuite( LuceneTest.class ); - } - - protected void configure(Configuration cfg) { - File sub = getBaseIndexDir(); - cfg.setProperty( Environment.INDEX_BASE_DIR, sub.getAbsolutePath() ); - cfg.setProperty( Environment.ANALYZER_CLASS, StopAnalyzer.class.getName() ); - LuceneEventListener del = new LuceneEventListener(); - cfg.getEventListeners().setPostCommitDeleteEventListeners( new PostDeleteEventListener[]{del} ); - cfg.getEventListeners().setPostCommitUpdateEventListeners( new PostUpdateEventListener[]{del} ); - cfg.getEventListeners().setPostCommitInsertEventListeners( new PostInsertEventListener[]{del} ); - } - -} - |
From: <hib...@li...> - 2006-06-26 22:23:38
|
Author: epbernard Date: 2006-06-26 18:23:32 -0400 (Mon, 26 Jun 2006) New Revision: 10051 Added: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/Car.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/MovingThing.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/PolymorphismTest.java trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/SportCar.java Log: tests on polymorphism Added: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/Car.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/Car.java 2006-06-25 16:27:43 UTC (rev 10050) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/Car.java 2006-06-26 22:23:32 UTC (rev 10051) @@ -0,0 +1,39 @@ +//$Id: $ +package org.hibernate.test.annotations.polymorphism; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; + +import org.hibernate.annotations.PolymorphismType; + +/** + * @author Emmanuel Bernard + */ +@Entity +@Inheritance(strategy= InheritanceType.TABLE_PER_CLASS) +...@or...notations.Entity(polymorphism = PolymorphismType.EXPLICIT) +public class Car extends MovingThing { + private Integer id; + private String model; + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + @Id @GeneratedValue(strategy = GenerationType.TABLE ) + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } +} Added: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/MovingThing.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/MovingThing.java 2006-06-25 16:27:43 UTC (rev 10050) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/MovingThing.java 2006-06-26 22:23:32 UTC (rev 10051) @@ -0,0 +1,8 @@ +//$Id: $ +package org.hibernate.test.annotations.polymorphism; + +/** + * @author Emmanuel Bernard + */ +public class MovingThing { +} Added: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/PolymorphismTest.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/PolymorphismTest.java 2006-06-25 16:27:43 UTC (rev 10050) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/PolymorphismTest.java 2006-06-26 22:23:32 UTC (rev 10051) @@ -0,0 +1,37 @@ +//$Id: $ +package org.hibernate.test.annotations.polymorphism; + +import org.hibernate.test.annotations.TestCase; +import org.hibernate.Session; +import org.hibernate.Transaction; + +/** + * @author Emmanuel Bernard + */ +public class PolymorphismTest extends TestCase { + + public void testPolymorphism() throws Exception { + Car car = new Car(); + car.setModel( "SUV" ); + SportCar car2 = new SportCar(); + car2.setModel( "350Z" ); + Session s = openSession(); + Transaction tx = s.beginTransaction(); + tx.begin(); + s.persist( car ); + s.persist( car2 ); + s.flush(); + assertEquals( 2, s.createQuery( "select car from Car car").list().size() ); + assertEquals( 0, s.createQuery( "select count(m) from " + MovingThing.class.getName() + " m").list().size() ); + tx.rollback(); + s.close(); + + } + + protected Class[] getMappings() { + return new Class[] { + Car.class, + SportCar.class + }; + } +} Added: trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/SportCar.java =================================================================== --- trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/SportCar.java 2006-06-25 16:27:43 UTC (rev 10050) +++ trunk/HibernateExt/metadata/src/test/org/hibernate/test/annotations/polymorphism/SportCar.java 2006-06-26 22:23:32 UTC (rev 10051) @@ -0,0 +1,13 @@ +//$Id: $ +package org.hibernate.test.annotations.polymorphism; + +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * @author Emmanuel Bernard + */ +@Entity +@Table(name = "sport_car") +public class SportCar extends Car { +} |
Author: max...@jb... Date: 2006-06-25 12:27:43 -0400 (Sun, 25 Jun 2006) New Revision: 10050 Added: trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/ trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/Group.java trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/QueryExporterTest.java trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/User.java trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/UserGroup.hbm.xml Modified: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/QueryExporter.java trunk/HibernateExt/tools/src/testsupport/anttest-build.xml Log: HBX-689 The query task throws NSE Modified: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/QueryExporter.java =================================================================== --- trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/QueryExporter.java 2006-06-25 14:37:50 UTC (rev 10049) +++ trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/QueryExporter.java 2006-06-25 16:27:43 UTC (rev 10050) @@ -44,7 +44,7 @@ getArtifactCollector().addFile( file, "query-output" ); for (Iterator iter1 = list.iterator(); iter1.hasNext();) { - Object element = iter.next(); + Object element = iter1.next(); pw.println(element); } Added: trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/Group.java =================================================================== --- trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/Group.java 2006-06-25 14:37:50 UTC (rev 10049) +++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/Group.java 2006-06-25 16:27:43 UTC (rev 10050) @@ -0,0 +1,56 @@ +//$Id: Group.java 7085 2005-06-08 17:59:47Z oneovthafew $ +package org.hibernate.tool.hbm2x.query; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +public class Group implements Serializable { + + private String org; + private String name; + private String description; + + private Set users = new HashSet(); + + public Group(String name, String org) { + this.org = org; + this.name = name; + } + + public Group() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getOrg() { + return org; + } + + public void setOrg(String org) { + this.org = org; + } + + public Set getUsers() { + return users; + } + + public void setUsers(Set users) { + this.users = users; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + +} Added: trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/QueryExporterTest.java =================================================================== --- trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/QueryExporterTest.java 2006-06-25 14:37:50 UTC (rev 10049) +++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/QueryExporterTest.java 2006-06-25 16:27:43 UTC (rev 10050) @@ -0,0 +1,66 @@ +package org.hibernate.tool.hbm2x.query; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.hibernate.SessionFactory; +import org.hibernate.cfg.Environment; +import org.hibernate.classic.Session; +import org.hibernate.tool.NonReflectiveTestCase; +import org.hibernate.tool.hbm2x.QueryExporter; + +public class QueryExporterTest extends NonReflectiveTestCase { + + public QueryExporterTest(String name) { + super( name ); + } + + protected String[] getMappings() { + return new String[] { "UserGroup.hbm.xml"}; + } + + protected String getBaseForMappings() { + return super.getBaseForMappings() + "hbm2x/query/"; + } + + String FILE = "queryresult.txt"; + + protected void setUp() throws Exception { + super.setUp(); + getCfg().setProperty( Environment.HBM2DDL_AUTO, "update" ); + SessionFactory factory = getCfg().buildSessionFactory(); + + Session s = factory.openSession(); + + User user = new User("max", "jboss"); + s.persist( user ); + + user = new User("gavin", "jboss"); + s.persist( user ); + + s.flush(); + + s.close(); + + QueryExporter exporter = new QueryExporter(); + exporter.setConfiguration( getCfg() ); + exporter.setOutputDirectory( getOutputDir() ); + exporter.setFilename( FILE ); + List queries = new ArrayList(); + queries.add("from java.lang.Object"); + exporter.setQueries( queries ); + + exporter.start(); + + } + + + public void testQueryExporter() { + + assertFileAndExists( new File(getOutputDir(), FILE )); + + + } + +} Added: trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/User.java =================================================================== --- trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/User.java 2006-06-25 14:37:50 UTC (rev 10049) +++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/User.java 2006-06-25 16:27:43 UTC (rev 10050) @@ -0,0 +1,46 @@ +//$Id: User.java 7085 2005-06-08 17:59:47Z oneovthafew $ +package org.hibernate.tool.hbm2x.query; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +public class User implements Serializable { + + private String org; + private String name; + private Set groups = new HashSet(); + + public User(String name, String org) { + this.org = org; + this.name = name; + } + + public User() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getOrg() { + return org; + } + + public void setOrg(String org) { + this.org = org; + } + + public Set getGroups() { + return groups; + } + + public void setGroups(Set groups) { + this.groups = groups; + } + +} Added: trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/UserGroup.hbm.xml =================================================================== --- trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/UserGroup.hbm.xml 2006-06-25 14:37:50 UTC (rev 10049) +++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/query/UserGroup.hbm.xml 2006-06-25 16:27:43 UTC (rev 10050) @@ -0,0 +1,52 @@ +<?xml version="1.0"?> +<!DOCTYPE hibernate-mapping PUBLIC + "-//Hibernate/Hibernate Mapping DTD 3.0//EN" + "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> + +<!-- + + This mapping demonstrates how to map a many-to-many + association with a shared attribute in the primary keys + of the associated entities. + +--> + +<hibernate-mapping + package="org.hibernate.tool.hbm2x.query"> + + <class name="User" table="`User`"> + <composite-id> + <key-property name="name"/> + <key-property name="org"/> + </composite-id> + <set name="groups" table="UserGroup"> + <key> + <column name="userName"/> + <column name="org"/> + </key> + <many-to-many class="Group"> + <column name="groupName"/> + <formula>org</formula> + </many-to-many> + </set> + </class> + + <class name="Group" table="`Group`"> + <composite-id> + <key-property name="name"/> + <key-property name="org"/> + </composite-id> + <property name="description"/> + <set name="users" table="UserGroup" inverse="true"> + <key> + <column name="groupName"/> + <column name="org"/> + </key> + <many-to-many class="User"> + <column name="userName"/> + <formula>org</formula> + </many-to-many> + </set> + </class> + +</hibernate-mapping> Modified: trunk/HibernateExt/tools/src/testsupport/anttest-build.xml =================================================================== --- trunk/HibernateExt/tools/src/testsupport/anttest-build.xml 2006-06-25 14:37:50 UTC (rev 10049) +++ trunk/HibernateExt/tools/src/testsupport/anttest-build.xml 2006-06-25 16:27:43 UTC (rev 10050) @@ -236,6 +236,8 @@ <target name="prepareCfg2hbm" description="prepare for cfg2hbm tasks"> <sql onerror="continue" driver="${hibernate.connection.driver_class}" url="${hibernate.connection.url}" userid="${hibernate.connection.username}" password="${hibernate.connection.password}" classpath="${hibernate-core.home}\jdbc\hsqldb.jar"> create table VeriSimplyTable ( id bigint not null, name varchar(255), primary key (id) ); + insert table VeriSimplyTable ( 1, "A Row"); + insert table VeriSimplyTable ( 2, "Another Row"); </sql> <delete dir="${build.dir}/cfg2hbm" failonerror="false" /> @@ -244,6 +246,7 @@ <target name="afterCfg2hbm" description="prepare for cfg2hbm tasks"> <sql onerror="continue" driver="${hibernate.connection.driver_class}" url="${hibernate.connection.url}" userid="${hibernate.connection.username}" password="${hibernate.connection.password}" classpath="${hibernate-core.home}\jdbc\hsqldb.jar"> + delete from VeriSimplyTable where id > 0; drop table VeriSimplyTable; </sql> @@ -328,7 +331,7 @@ </hibernatetool> </target> - <target name="testquery" description="test the query tasks"> + <target name="testquery" depends="prepareCfg2hbm" description="test the query tasks"> <taskdef name="hibernatetool" classname="org.hibernate.tool.ant.HibernateToolTask" classpathref="tasks.classpath" /> <hibernatetool destdir="${build.dir}/querytest"> <configuration propertyfile="../../etc/hibernate.properties" configurationfile="querytest-hibernate.cfg.xml" /> @@ -338,5 +341,7 @@ </query> <query destfile="queryresult.txt">from java.io.Serializable</query> </hibernatetool> + + <antcall target="afterCfg2hbm" /> </target> </project> |
From: <hib...@li...> - 2006-06-25 14:38:04
|
Author: max...@jb... Date: 2006-06-25 10:37:50 -0400 (Sun, 25 Jun 2006) New Revision: 10049 Modified: trunk/HibernateExt/tools/lib/testlibs/jboss-seam.jar Log: update seam jar Modified: trunk/HibernateExt/tools/lib/testlibs/jboss-seam.jar =================================================================== (Binary files differ) |
From: <hib...@li...> - 2006-06-25 14:37:16
|
Author: max...@jb... Date: 2006-06-25 10:37:09 -0400 (Sun, 25 Jun 2006) New Revision: 10048 Modified: trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCToHibernateTypeHelper.java trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/DefaultReverseEngineeringStrategyTest.java Log: HBX-693 Database columns with non-null integer data type maps to Java "Integer" instead of "int" Modified: trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCToHibernateTypeHelper.java =================================================================== --- trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCToHibernateTypeHelper.java 2006-06-25 14:36:12 UTC (rev 10047) +++ trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCToHibernateTypeHelper.java 2006-06-25 14:37:09 UTC (rev 10048) @@ -73,7 +73,7 @@ return returnNullable?Short.class.getName():"short"; } else if (precision < 10) { - return returnNullable?Integer.class.getName():"integer"; + return returnNullable?Integer.class.getName():"int"; } else if (precision < 19) { return returnNullable?Long.class.getName():"long"; Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/DefaultReverseEngineeringStrategyTest.java =================================================================== --- trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/DefaultReverseEngineeringStrategyTest.java 2006-06-25 14:36:12 UTC (rev 10047) +++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/test/jdbc2cfg/DefaultReverseEngineeringStrategyTest.java 2006-06-25 14:37:09 UTC (rev 10048) @@ -107,6 +107,8 @@ public void testPreferredTypes() { assertEquals("int",rns.columnToHibernateTypeName(null, "bogus",Types.INTEGER,0,0,0, false, false)); + assertEquals("because nullable it should not be int", "java.lang.Integer",rns.columnToHibernateTypeName(null, "bogus",Types.INTEGER,0,0,0, true, false)); + assertEquals("java.lang.Integer",rns.columnToHibernateTypeName(null, "bogus",Types.NUMERIC,0,9,0, true, false)); assertEquals("java.lang.Integer",rns.columnToHibernateTypeName(null, "bogus",Types.INTEGER,0,0,0, true, false)); assertEquals("serializable",rns.columnToHibernateTypeName(new TableIdentifier("sdf"), "bogus",-567,0,0,0, false, false)); |
From: <hib...@li...> - 2006-06-25 14:36:17
|
Author: max...@jb... Date: 2006-06-25 10:36:12 -0400 (Sun, 25 Jun 2006) New Revision: 10047 Modified: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/Version.java Log: Modified: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/Version.java =================================================================== --- trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/Version.java 2006-06-25 14:34:17 UTC (rev 10046) +++ trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/Version.java 2006-06-25 14:36:12 UTC (rev 10047) @@ -5,7 +5,7 @@ final public class Version { - public static final String VERSION = "3.1.0.beta5"; + public static final String VERSION = "3.2.0.beta6"; private static final Version instance = new Version(); |
From: <hib...@li...> - 2006-06-25 14:34:22
|
Author: max...@jb... Date: 2006-06-25 10:34:17 -0400 (Sun, 25 Jun 2006) New Revision: 10046 Modified: trunk/HibernateExt/tools/etc/hibernate.properties Log: Modified: trunk/HibernateExt/tools/etc/hibernate.properties =================================================================== --- trunk/HibernateExt/tools/etc/hibernate.properties 2006-06-25 14:11:54 UTC (rev 10045) +++ trunk/HibernateExt/tools/etc/hibernate.properties 2006-06-25 14:34:17 UTC (rev 10046) @@ -19,6 +19,18 @@ #hibernate.connection.password db2 +## H2 (www.h2database.com) +#hibernate.dialect org.hibernate.dialect.H2Dialect +#hibernate.connection.driver_class org.h2.Driver +#hibernate.connection.username sa +#hibernate.connection.password +#hibernate.connection.url jdbc:h2:testdb/h2test +#hibernate.connection.url jdbc:h2:mem: +#hibernate.connection.url jdbc:h2:tcp://dbserv:8084/sample; +#hibernate.connection.url jdbc:h2:ssl://secureserv:8085/sample; +#hibernate.connection.url jdbc:h2:ssl://secureserv/testdb;cipher=AES + + ## HypersonicSQL hibernate.dialect org.hibernate.dialect.HSQLDialect @@ -26,10 +38,10 @@ hibernate.connection.username sa hibernate.connection.password #hibernate.connection.url jdbc:hsqldb:hsql://localhost -hibernate.connection.url jdbc:hsqldb:test +hibernate.connection.url jdbc:hsqldb:testdb/hsqldb;shutdown=true #hibernate.connection.url jdbc:hsqldb:. +#hibernate.connection.shutdown=true - ## MySQL #hibernate.dialect org.hibernate.dialect.MySQLDialect @@ -294,8 +306,8 @@ ## specify a default schema and catalog for unqualified tablenames -#hibernate.default_schema -#hibernate.default_catalog +hibernate.default_schema PUBLIC +#hibernate.default_catalog PUBLIC ## set the maximum depth of the outer join fetch tree |
From: <hib...@li...> - 2006-06-25 14:12:00
|
Author: max...@jb... Date: 2006-06-25 10:11:54 -0400 (Sun, 25 Jun 2006) New Revision: 10045 Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Hbm2SeamTest.java Log: adjust test for new components.xml in seam templates. Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Hbm2SeamTest.java =================================================================== --- trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Hbm2SeamTest.java 2006-06-25 07:37:06 UTC (rev 10044) +++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/Hbm2SeamTest.java 2006-06-25 14:11:54 UTC (rev 10045) @@ -46,7 +46,7 @@ assertEquals(12,artifactCollector.getFileCount("java")); assertEquals(1,artifactCollector.getFileCount("html")); assertEquals(4,artifactCollector.getFileCount("jsp")); - assertEquals(6,artifactCollector.getFileCount("xml")); + assertEquals(7,artifactCollector.getFileCount("xml")); assertEquals(3,artifactCollector.getFileCount("properties")); assertEquals(1,artifactCollector.getFileCount("txt")); assertEquals(1,artifactCollector.getFileCount("css")); |
From: <hib...@li...> - 2006-06-25 07:37:13
|
Author: caoxg Date: 2006-06-25 03:37:06 -0400 (Sun, 25 Jun 2006) New Revision: 10044 Modified: trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/fopdf.xsl trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html.xsl trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html_chunk.xsl Log: Modified: trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/fopdf.xsl =================================================================== --- trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/fopdf.xsl 2006-06-25 07:29:48 UTC (rev 10043) +++ trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/fopdf.xsl 2006-06-25 07:37:06 UTC (rev 10044) @@ -44,9 +44,6 @@ <fo:external-graphic src="file:images/hibernate_logo_a.png"/> </fo:block> <fo:block font-family="Helvetica" font-size="22pt" padding-before="10mm"> - <xsl:value-of select="bookinfo/title"/> - </fo:block> - <fo:block font-family="Helvetica" font-size="18pt" padding-before="10mm"> <xsl:value-of select="bookinfo/subtitle"/> </fo:block> <fo:block font-family="Helvetica" font-size="12pt" padding="10mm"> @@ -272,6 +269,7 @@ <xsl:attribute name="font-size">0.8em</xsl:attribute> </xsl:attribute-set> + <!--################################################### Tables ################################################### --> @@ -300,23 +298,6 @@ <xsl:param name="section.autolabel" select="1"/> <xsl:param name="section.label.includes.component.label" select="1"/> - <!-- Label only Sections up to level 2 --> - <xsl:param name="local.l10n.xml" select="document('')"/> - <l:i18n xmlns:l="http://docbook.sourceforge.net/xmlns/l10n/1.0"> - <l:l10n language="en"> - <l:context name="title-numbered"> - <l:template name="sect3" text="%t"/> - <l:template name="sect4" text="%t"/> - <l:template name="sect5" text="%t"/> - </l:context> - <l:context name="section-xref-numbered"> - <l:template name="sect3" text="the section called %t"/> - <l:template name="sect4" text="the section called %t"/> - <l:template name="sect5" text="the section called %t"/> - </l:context> - </l:l10n> - </l:i18n> - <!--################################################### Titles ################################################### --> @@ -516,4 +497,13 @@ --> <xsl:param name="draft.mode" select="'no'"/> + <!-- Simplified Chinese related Settings --> + <xsl:param name="hyphenate">false</xsl:param> + <xsl:param name="body.font.family">simsun</xsl:param> + <xsl:param name="monospace.font.family">simsun</xsl:param> + <xsl:param name="title.font.family">simhei</xsl:param> + <xsl:param name="saxon.character.representation" select="native"/> + <xsl:param name="callout.unicode" select="1"/> + <xsl:param name="callout.unicode.start.character" select="10102"/> + <xsl:param name="l10n.gentext.default.language" select="zh-cn"/> </xsl:stylesheet> Modified: trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html.xsl =================================================================== --- trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html.xsl 2006-06-25 07:29:48 UTC (rev 10043) +++ trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html.xsl 2006-06-25 07:37:06 UTC (rev 10044) @@ -15,7 +15,7 @@ --> <!DOCTYPE xsl:stylesheet [ - <!ENTITY db_xsl_path "../../../../../../Hibernate3/doc/reference/support/docbook-xsl/"> + <!ENTITY db_xsl_path "../../support/docbook-xsl/"> ]> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" Modified: trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html_chunk.xsl =================================================================== --- trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html_chunk.xsl 2006-06-25 07:29:48 UTC (rev 10043) +++ trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html_chunk.xsl 2006-06-25 07:37:06 UTC (rev 10044) @@ -15,7 +15,7 @@ --> <!DOCTYPE xsl:stylesheet [ - <!ENTITY db_xsl_path "../../../../../../Hibernate3/doc/reference/support/docbook-xsl/"> + <!ENTITY db_xsl_path "../../support/docbook-xsl/"> ]> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
From: <hib...@li...> - 2006-06-25 07:36:37
|
Author: caoxg Date: 2006-06-25 03:29:48 -0400 (Sun, 25 Jun 2006) New Revision: 10043 Added: trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/ trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/simhei.ttf trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/simhei.xml trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/simsun.ttc trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/simsun.xml trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/userconfig.xml Log: Added: trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/simhei.ttf =================================================================== (Binary files differ) Property changes on: trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/simhei.ttf ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/simhei.xml =================================================================== --- trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/simhei.xml 2006-06-23 15:45:46 UTC (rev 10042) +++ trunk/HibernateExt/metadata/doc/reference/zh_cn/fop/simhei.xml 2006-06-25 07:29:48 UTC (rev 10043) @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<font-metrics type="TYPE0"><font-name>SimHei</font-name><embed/><cap-height>0</cap-height><x-height>0</x-height><ascender>859</ascender><descender>-140</descender><bbox><left>0</left><bottom>-140</bottom><right>996</right><top>855</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf us="32" ue="126" gi="3"/><bf us="127" ue="127" gi="2"/><bf us="164" ue="164" gi="98"/><bf us="167" ue="168" gi="99"/><bf us="176" ue="177" gi="101"/><bf us="183" ue="183" gi="103"/><bf us="215" ue="215" gi="104"/><bf us="224" ue="225" gi="105"/><bf us="232" ue="234" gi="107"/><bf us="236" ue="237" gi="110"/><bf us="242" ue="243" gi="112"/><bf us="247" ue="247" gi="114"/><bf us="249" ue="250" gi="115"/><bf us="252" ue="252" gi="117"/><bf us="257" ue="257" gi="118"/><bf us="275" ue="275" gi="119"/><bf us="283" ue="283" gi="120"/><bf us="299" ue="299" gi="121"! /><bf us="324" ue="324" gi="122"/><bf us="328" ue="328" gi="123"/><bf us="333" ue="333" gi="124"/><bf us="363" ue="363" gi="125"/><bf us="462" ue="462" gi="126"/><bf us="464" ue="464" gi="127"/><bf us="466" ue="466" gi="128"/><bf us="468" ue="468" gi="129"/><bf us="470" ue="470" gi="130"/><bf us="472" ue="472" gi="131"/><bf us="474" ue="474" gi="132"/><bf us="476" ue="476" gi="133"/><bf us="505" ue="505" gi="687"/><bf us="593" ue="593" gi="134"/><bf us="609" ue="609" gi="135"/><bf us="711" ue="711" gi="136"/><bf us="713" ue="713" gi="137"/><bf us="714" ue="715" gi="799"/><bf us="729" ue="729" gi="801"/><bf us="913" ue="929" gi="138"/><bf us="931" ue="937" gi="155"/><bf us="945" ue="961" gi="162"/><bf us="963" ue="969" gi="179"/><bf us="1025" ue="1025" gi="186"/><bf us="1040" ue="1103" gi="187"/><bf us="1105" ue="1105" gi="251"/><bf us="8208" ue="8208" gi="971"/><bf us="8211" ue="8211" gi="802"/><bf us="8212" ue="8212" gi="252"/><bf us="8213" ue="8213" gi="803"/><bf us="8214! " ue="8214" gi="253"/><bf us="8216" ue="8217" gi="254"/><bf us="8220" ue="8221" gi="256"/><bf us="8229" ue="8229" gi="804"/><bf us="8230" ue="8230" gi="258"/><bf us="8240" ue="8240" gi="259"/><bf us="8242" ue="8243" gi="260"/><bf us="8245" ue="8245" gi="805"/><bf us="8251" ue="8251" gi="262"/><bf us="8451" ue="8451" gi="263"/><bf us="8453" ue="8453" gi="806"/><bf us="8457" ue="8457" gi="807"/><bf us="8470" ue="8470" gi="264"/><bf us="8481" ue="8481" gi="969"/><bf us="8544" ue="8555" gi="265"/><bf us="8560" ue="8569" gi="957"/><bf us="8592" ue="8595" gi="277"/><bf us="8598" ue="8601" gi="808"/><bf us="8712" ue="8712" gi="281"/><bf us="8719" ue="8719" gi="282"/><bf us="8721" ue="8721" gi="283"/><bf us="8725" ue="8725" gi="812"/><bf us="8730" ue="8730" gi="284"/><bf us="8733" ue="8734" gi="285"/><bf us="8735" ue="8735" gi="813"/><bf us="8736" ue="8736" gi="287"/><bf us="8739" ue="8739" gi="814"/><bf us="8741" ue="8741" gi="288"/><bf us="8743" ue="8747" gi="289"/><bf us="8750" ue="8750" gi="294"/><bf us="8756" ue="8759" gi="295"/><bf us="8765" ue=! "8765" gi="299"/><bf us="8776" ue="8776" gi="300"/><bf us="8780" ue="8780" gi="301"/><bf us="8786" ue="8786" gi="815"/><bf us="8800" ue="8801" gi="302"/><bf us="8804" ue="8805" gi="304"/><bf us="8806" ue="8807" gi="816"/><bf us="8814" ue="8815" gi="306"/><bf us="8853" ue="8853" gi="880"/><bf us="8857" ue="8857" gi="308"/><bf us="8869" ue="8869" gi="309"/><bf us="8895" ue="8895" gi="818"/><bf us="8978" ue="8978" gi="310"/><bf us="9312" ue="9321" gi="311"/><bf us="9332" ue="9371" gi="321"/><bf us="9472" ue="9547" gi="361"/><bf us="9552" ue="9587" gi="819"/><bf us="9601" ue="9615" gi="855"/><bf us="9619" ue="9621" gi="870"/><bf us="9632" ue="9633" gi="437"/><bf us="9650" ue="9651" gi="439"/><bf us="9660" ue="9661" gi="873"/><bf us="9670" ue="9671" gi="441"/><bf us="9675" ue="9675" gi="443"/><bf us="9678" ue="9679" gi="444"/><bf us="9698" ue="9701" gi="875"/><bf us="9733" ue="9734" gi="446"/><bf us="9737" ue="9737" gi="879"/><bf us="9792" ue="9792" gi="448"/><bf us="9794" ue="9! 794" gi="449"/><bf us="11905" ue="11905" gi="21903"/><bf us="11908" ue ="11908" gi="21907"/><bf us="11912" ue="11912" gi="21910"/><bf us="11915" ue="11915" gi="21911"/><bf us="11916" ue="11916" gi="21916"/><bf us="11943" ue="11943" gi="21930"/><bf us="11946" ue="11946" gi="21933"/><bf us="11950" ue="11950" gi="21936"/><bf us="11955" ue="11955" gi="21938"/><bf us="11958" ue="11959" gi="21939"/><bf us="11963" ue="11963" gi="21944"/><bf us="11978" ue="11978" gi="21954"/><bf us="12272" ue="12283" gi="689"/><bf us="12288" ue="12291" gi="450"/><bf us="12293" ue="12293" gi="454"/><bf us="12294" ue="12294" gi="977"/><bf us="12295" ue="12295" gi="21983"/><bf us="12296" ue="12305" gi="455"/><bf us="12306" ue="12306" gi="881"/><bf us="12307" ue="12311" gi="465"/><bf us="12317" ue="12318" gi="882"/><bf us="12321" ue="12329" gi="884"/><bf us="12353" ue="12435" gi="470"/><bf us="12443" ue="12444" gi="973"/><bf us="12445" ue="12446" gi="978"/><bf us="12449" ue="12534" gi="553"/><bf us="12540" ue="12540" gi="972"/><bf us="12541" ue="12542" gi="975"/><bf us="12! 549" ue="12585" gi="639"/><bf us="12832" ue="12841" gi="676"/><bf us="12849" ue="12849" gi="970"/><bf us="12963" ue="12963" gi="893"/><bf us="13198" ue="13199" gi="894"/><bf us="13212" ue="13214" gi="896"/><bf us="13217" ue="13217" gi="899"/><bf us="13252" ue="13252" gi="900"/><bf us="13262" ue="13262" gi="901"/><bf us="13265" ue="13266" gi="902"/><bf us="13269" ue="13269" gi="904"/><bf us="13383" ue="13383" gi="21909"/><bf us="13427" ue="13427" gi="21908"/><bf us="13726" ue="13726" gi="21913"/><bf us="13838" ue="13838" gi="21915"/><bf us="13850" ue="13850" gi="21914"/><bf us="14616" ue="14616" gi="21919"/><bf us="14702" ue="14702" gi="21918"/><bf us="14799" ue="14799" gi="21921"/><bf us="14800" ue="14800" gi="21924"/><bf us="14815" ue="14815" gi="21922"/><bf us="14963" ue="14963" gi="21923"/><bf us="15182" ue="15182" gi="21927"/><bf us="15470" ue="15470" gi="21928"/><bf us="15584" ue="15584" gi="21929"/><bf us="16470" ue="16470" gi="21934"/><bf us="16735" ue="16735" gi="21! 935"/><bf us="17207" ue="17207" gi="21937"/><bf us="17324" ue="17324" gi="21943"/><bf us="17329" ue="17329" gi="21942"/><bf us="17373" ue="17373" gi="21945"/><bf us="17622" ue="17622" gi="21946"/><bf us="17996" ue="17996" gi="21948"/><bf us="18017" ue="18017" gi="21947"/><bf us="18211" ue="18211" gi="21950"/><bf us="18217" ue="18217" gi="21951"/><bf us="18300" ue="18300" gi="21952"/><bf us="18317" ue="18317" gi="21953"/><bf us="18759" ue="18759" gi="21955"/><bf us="18810" ue="18810" gi="21956"/><bf us="18813" ue="18813" gi="21957"/><bf us="18818" ue="18819" gi="21958"/><bf us="18821" ue="18822" gi="21960"/><bf us="18843" ue="18843" gi="21963"/><bf us="18847" ue="18847" gi="21962"/><bf us="18870" ue="18870" gi="21965"/><bf us="18871" ue="18871" gi="21964"/><bf us="19575" ue="19575" gi="21972"/><bf us="19615" ue="19615" gi="21969"/><bf us="19617" ue="19617" gi="21971"/><bf us="19618" ue="19618" gi="21973"/><bf us="19619" ue="19619" gi="21968"/><bf us="19629" ue="19629" gi="21970"/><bf us="19731" ue="19737" gi="21974"/><bf us="19886" ue="19886" g! i="21981"/><bf us="19968" ue="40869" gi="980"/><bf us="59335" ue="59336" gi="686"/><bf us="59367" ue="59379" gi="688"/><bf us="59413" ue="59492" gi="21903"/><bf us="63788" ue="63788" gi="21882"/><bf us="63865" ue="63865" gi="21883"/><bf us="63893" ue="63893" gi="21884"/><bf us="63975" ue="63975" gi="21885"/><bf us="63985" ue="63985" gi="21886"/><bf us="64012" ue="64015" gi="21887"/><bf us="64017" ue="64017" gi="21891"/><bf us="64019" ue="64020" gi="21892"/><bf us="64024" ue="64024" gi="21894"/><bf us="64031" ue="64033" gi="21895"/><bf us="64035" ue="64036" gi="21898"/><bf us="64039" ue="64041" gi="21900"/><bf us="65072" ue="65073" gi="905"/><bf us="65075" ue="65092" gi="907"/><bf us="65097" ue="65106" gi="925"/><bf us="65108" ue="65111" gi="935"/><bf us="65113" ue="65126" gi="939"/><bf us="65128" ue="65131" gi="953"/><bf us="65281" ue="65374" gi="701"/><bf us="65504" ue="65505" gi="795"/><bf us="65506" ue="65506" gi="967"/><bf us="65507" ue="65507" gi="797"/><bf us="65508" ! ue="65508" gi="968"/><bf us="65509" ue="65509" gi="798"/><bf us="65535 " ue="65535" gi="0"/></bfranges><cid-widths start-index="0"><wx w="1000"/><wx w="0"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="! 500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w! x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000! "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w! ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>! <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1! 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx! w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000! "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=! "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="500"/><wx w="500"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w! x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000! "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w! ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>! <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1! 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx! w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000! "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=! "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>! <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/> <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10! 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx! w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"! /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=! "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w= "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><! wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10! 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx ! w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"! /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000" /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="! 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><! wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>< wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100! 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx ! w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/! ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="! 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=" 1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w! x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100! 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="100 0"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w! ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/! ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/ ><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1! 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w! x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><w x w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000! "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w! ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w ="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>! <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1! 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1 000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx! w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000! "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000 "/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w=! "1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/>! <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/> <wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="10! 00"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx! w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"! /><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="1000"/><wx w="... [truncated message content] |
From: <hib...@li...> - 2006-06-23 15:45:50
|
Author: epbernard Date: 2006-06-23 11:45:46 -0400 (Fri, 23 Jun 2006) New Revision: 10042 Added: trunk/HibernateExt/metadata/doc/reference/zh_cn/ trunk/HibernateExt/metadata/doc/reference/zh_cn/images/ trunk/HibernateExt/metadata/doc/reference/zh_cn/images/hibernate_logo_a.png trunk/HibernateExt/metadata/doc/reference/zh_cn/master.xml trunk/HibernateExt/metadata/doc/reference/zh_cn/modules/ trunk/HibernateExt/metadata/doc/reference/zh_cn/modules/entity.xml trunk/HibernateExt/metadata/doc/reference/zh_cn/modules/lucene.xml trunk/HibernateExt/metadata/doc/reference/zh_cn/modules/setup.xml trunk/HibernateExt/metadata/doc/reference/zh_cn/modules/validator.xml trunk/HibernateExt/metadata/doc/reference/zh_cn/modules/xml-overriding.xml trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/ trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/fopdf.xsl trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html.css trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html.xsl trunk/HibernateExt/metadata/doc/reference/zh_cn/styles/html_chunk.xsl Modified: trunk/HibernateExt/metadata/doc/reference/build.xml Log: ANN-378 Chinese translation Modified: trunk/HibernateExt/metadata/doc/reference/build.xml =================================================================== --- trunk/HibernateExt/metadata/doc/reference/build.xml 2006-06-22 20:07:07 UTC (rev 10041) +++ trunk/HibernateExt/metadata/doc/reference/build.xml 2006-06-23 15:45:46 UTC (rev 10042) @@ -12,7 +12,10 @@ <param name="docname" value="hibernate_annotations"/> <param name="lang" value="en"/> </antcall> - + <antcall target="lang.all"> + <param name="docname" value="hibernate_annotations"/> + <param name="lang" value="zh_cn"/> + </antcall> </target> </project> Added: trunk/HibernateExt/metadata/doc/reference/zh_cn/images/hibernate_logo_a.png =================================================================== (Binary files differ) Property changes on: trunk/HibernateExt/metadata/doc/reference/zh_cn/images/hibernate_logo_a.png ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/HibernateExt/metadata/doc/reference/zh_cn/master.xml =================================================================== --- trunk/HibernateExt/metadata/doc/reference/zh_cn/master.xml 2006-06-22 20:07:07 UTC (rev 10041) +++ trunk/HibernateExt/metadata/doc/reference/zh_cn/master.xml 2006-06-23 15:45:46 UTC (rev 10042) @@ -0,0 +1,294 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN" +"../../../../../Hibernate3/doc/reference/support/docbook-dtd/docbookx.dtd" [ +<!ENTITY setup SYSTEM "modules/setup.xml"> +<!ENTITY entity SYSTEM "modules/entity.xml"> +<!ENTITY xml-overriding SYSTEM "modules/xml-overriding.xml"> +<!ENTITY validator SYSTEM "modules/validator.xml"> +<!ENTITY lucene SYSTEM "modules/lucene.xml"> +]> +<book lang="zh_cn"> + <bookinfo> + <title>Hibernate Annotations</title> + + <subtitle>参考文档</subtitle> + + <releaseinfo>3.2.0 CR1</releaseinfo> + + <mediaobject> + <imageobject> + <imagedata fileref="images/hibernate_logo_a.png" format="png" /> + </imageobject> + </mediaobject> + </bookinfo> + + <toc></toc> + + <preface id="preface" revision="2"> + <title>前言</title> + + <para>WARNING! This is a translated version of the English Hibernate + reference documentation. The translated version might not be up to date! + However, the differences should only be very minor. Consult the English + reference documentation if you are missing information or encounter a + translation error. If you like to contribute to a particular translation, + contact us on the Hibernate developer mailing list.</para> + + <para>Translator(s): RedSaga Translate Team 满江红翻译团队 + <ca...@ya...></para> + + <sect1 id="preface-translate-comments-zh-cn"> + <title>翻译说明</title> + + <para>本文档的翻译是在网络上协作进行的,也会不断根据Hibernate的升级进行更新。提供此文档的目的是为了减缓学习Hibernate的坡度,而非代替原文档。我们建议所有有能力的读者都直接阅读英文原文。若您对翻译有异议,或发现翻译错误,敬请不吝赐教,报告到如下地址:http://wiki.redsaga.com/confluence/display/HART/Home</para> + + <table frame="topbot" id="redsaga-translate-team"> + <title>Hibernate Annotation v3翻译团队</title> + + <tgroup cols="6" colsep="1" rowsep="1"> + <colspec colname="c1" colwidth="1*" /> + + <colspec colname="c2" colwidth="2*" /> + + <colspec colname="c3" colwidth="2*" /> + + <colspec colname="c4" colwidth="2*" /> + + <colspec colname="c5" colwidth="2*" /> + + <thead> + <row> + <entry align="center">序号</entry> + + <entry align="center">标题</entry> + + <entry align="center">中文标题</entry> + + <entry align="center">翻译</entry> + + <entry align="center">1审</entry> + + <entry align="center"> 2审</entry> + </row> + </thead> + + <tbody> + <row> + <entry>--</entry> + + <entry>Contents</entry> + + <entry>目录</entry> + + <entry>Liu Chang</entry> + + <entry></entry> + + <entry></entry> + </row> + + <row> + <entry>#1</entry> + + <entry>Setting up an annotations projec</entry> + + <entry>创建一个注解项目</entry> + + <entry>melthaw</entry> + + <entry>Zheng Shuai</entry> + + <entry>superq</entry> + </row> + + <row> + <entry>#2</entry> + + <entry>Entity Beans-Introduction</entry> + + <entry>实体Bean-简介</entry> + + <entry>melthaw</entry> + + <entry>Zheng Shuai</entry> + + <entry>superq</entry> + </row> + + <row> + <entry>#3</entry> + + <entry>Entity Beans-Mapping with EJB3 Annotations</entry> + + <entry>实体Bean-用EJB3注解进行映射</entry> + + <entry>melthaw</entry> + + <entry>Zheng Shuai</entry> + + <entry>superq, Liu Chang, Sean Chan</entry> + </row> + + <row> + <entry>#4</entry> + + <entry>Entity Beans-Mapping Queries</entry> + + <entry>实体Bean-映射查询</entry> + + <entry>melthaw</entry> + + <entry>Zheng Shuai</entry> + + <entry>superq, Liu Chang, Sean Chan</entry> + </row> + + <row> + <entry>#5</entry> + + <entry>Entity Beans-Hibernate Annotation Extensions</entry> + + <entry>实体Bean-Hibernate独有的注解扩展</entry> + + <entry>Sean Chan</entry> + + <entry>morning</entry> + + <entry>melthaw</entry> + </row> + + <row> + <entry>#6</entry> + + <entry>Overriding metadata through XML</entry> + + <entry>通过XML覆写元数据</entry> + + <entry>icess</entry> + + <entry>melthaw</entry> + + <entry>Sean Chan</entry> + </row> + + <row> + <entry>#7</entry> + + <entry>Hibernate Validator</entry> + + <entry>Hibernate验证器</entry> + + <entry>DigitalSonic</entry> + + <entry>morning</entry> + + <entry>melthaw</entry> + </row> + + <row> + <entry>#8</entry> + + <entry>Hibernate Lucene Integration</entry> + + <entry>Hibernate与Lucene集成</entry> + + <entry>mochow</entry> + + <entry>morning</entry> + + <entry>melthaw</entry> + </row> + + <row> + <entry>#9</entry> + + <entry>Appendix:Glossary</entry> + + <entry>附录:术语表</entry> + + <entry>mochow</entry> + + <entry>Liu Chang</entry> + + <entry>曹晓钢</entry> + </row> + </tbody> + </tgroup> + </table> + + <para>关于我们</para> + + <variablelist spacing="compact"> + <varlistentry> + <term>满江红.开源, http://www.redsaga.com</term> + + <listitem> + <para>从成立之初就致力于Java开放源代码在中国的传播与发展,与国内多个Java团体及出版社有深入交流。坚持少说多做的原则,目前有两个团队,“OpenDoc团队”与“翻译团队”,本翻译文档即为翻译团队作品。OpenDoc团队已经推出包括Hibernate、iBatis、Spring、WebWork的多份开放文档,并于2005年5月在Hibernate开放文档基础上扩充成书,出版了原创书籍:《深入浅出Hibernate》,本书400余页,适合各个层次的Hibernate用户。(http://www.redsaga.com/hibernate_book.html)敬请支持。</para> + </listitem> + </varlistentry> + + <varlistentry> + <term>致谢</term> + + <listitem> + <para>在我们翻译Hibernate + Annotation参考文档的同时,还有一位热心的朋友也在进行着同样的工作,这位朋友就是icess(冰雨),由icess翻译的中文版的地址: + http://icess.my.china.com/hibernate/a/ref/index.htm</para> + </listitem> + </varlistentry> + </variablelist> + </sect1> + + <sect1 id="preface-translate-licence-zh-cn"> + <title>版权声明</title> + + <para>Hibernate英文文档属于Hibernate发行包的一部分,遵循LGPL协议。本翻译版本同样遵循LGPL协议。参与翻译的译者一致同意放弃除署名权外对本翻译版本的其它权利要求。</para> + + <para>您可以自由链接、下载、传播此文档,或者放置在您的网站上,甚至作为产品的一部分发行。但前提是必须保证全文完整转载,包括完整的版权信息和作译者声明,并不能违反LGPL协议。这里“完整”的含义是,不能进行任何删除/增添/注解。若有删除/增添/注解,必须逐段明确声明那些部分并非本文档的一部分。</para> + </sect1> + </preface> + + <preface> + <title>前言</title> + + <para>正如其他的ORM工具,Hibernate同样需要元数据来控制在不同数据表达形式之间的转化. 在Hibernate + 2.x里,多数情况下表示映射关系的元数据保存在XML文本文件中. + 还有一种方式就是Xdoclet,它可以在编译时利用Javadoc中的源码注释信息来进行预处理. + 现在新的JDK标准(JDK1.5以上)也支持类似的注解功能,但相比之下很多工具对此提供了更强大更好用的支持. 以IntelliJ + IDEA和Eclipse为例,这些IDE工具为JDK 5.0注解功能提供了自动完成和语法高亮功能. 注解被直接编译到字节码里,并 + 在运行时(对于Hibernate来讲就是启动的时候)通过反射读取这些注解, 因此外部XML文件就不再需要了.</para> + + <para>EJB3规范最终认可了透明化ORM的成功范例以及市场对于这种技术的兴趣. + EJB3规范标准化了ORM的基础API而且在任何ORM持久化机制中使用元数据. <emphasis>Hibernate + EntityManager</emphasis>实现了EJB3持久化规范中定义的编程接口和生命周期规则. 在<emphasis>Hibernate + Core</emphasis>的基础上再结合 <emphasis>Hibernate + Annotations</emphasis>就实现了一套完整(并且独立)的EJB3持久化解决方案. + 你可以结合三者来使用,也可以抛开EJB3编程接口和生命周期规则而独立使用注解, 甚至只单独使用<emphasis>Hibernate + Core</emphasis>. 这些都取决于项目的商业和技术上的实际需求. Hibernate允许你直接使用native APIs,如果有需要, + 甚至可以直接操作JDBC和SQL.</para> + + <para>注意本文档基于Hibernate Annotations的预览版(遵从EJB 3.0/JSR-220最终草案). + 这个版本和新规范中定义的最终概念已经非常接近了.我们的目标是提供一套完整的ORM注解, + 包括EJB3的标准注解以及Hibernate3的扩展(后者是EJB3规范中没有涉及到的). 最终通过注解你可以完成任何可能的映射.详情参考<xref + linkend="compliance" />.</para> + + <para>EJB3最终草案修改了部分注解, + http://www.hibernate.org/371.html提供了从上一个版本到最新版本的迁移指南.</para> + </preface> + + &setup; + + &entity; + + &xml-overriding; + + &validator; + + &lucene; + + <appendix> + <title id="glossary">术语表</title> + + <para>Redsaga的wiki上维护了本文翻译过程中所参照的中英文对照的术语表,地址:http://wiki.redsaga.com/confluence/display/HART/glossary.</para> + </appendix> +</book> \ No newline at end of file Added: trunk/HibernateExt/metadata/doc/reference/zh_cn/modules/entity.xml =================================================================== --- trunk/HibernateExt/metadata/doc/reference/zh_cn/modules/entity.xml 2006-06-22 20:07:07 UTC (rev 10041) +++ trunk/HibernateExt/metadata/doc/reference/zh_cn/modules/entity.xml 2006-06-23 15:45:46 UTC (rev 10042) @@ -0,0 +1,2857 @@ +<?xml version="1.0" encoding="UTF-8"?> +<chapter id="entity"> + <title>实体Bean</title> + + <sect1 id="entity-overview" revision="1"> + <title>简介</title> + + <para>本章内容覆盖了EJB3.0实体bean的注解规范以及Hibernate特有的扩展.</para> + </sect1> + + <sect1 id="mapping" revision="1"> + <title>用EJB3注解进行映射</title> + + <para>现在EJB3实体Bean是纯粹的POJO.实际上这表达了和Hibernate持久化实体对象同样的概念. + 它们的映射都通过JDK5.0注解来定义(EJB3规范中的XML描述语法至今还没有最终定下来). + 注解分为两个部分,分别是逻辑映射注解和物理映射注解, + 通过逻辑映射注解可以描述对象模型,类之间的关系等等, + 而物理映射注解则描述了物理的schema,表,列,索引等等. + 下面我们在代码中将混合使用这两种类型的注解.</para> + + <para>EJB3注解的API定义在<literal>javax.persistence.*</literal>包里面. + 大部分和JDK5兼容的IDE(象Eclipse, IntelliJ IDEA 和Netbeans等等)都提供了注解接口和属性的自动完成功能. + (这些不需要IDE提供特别的EJB3支持模块,因为EJB3注解是标准的JDK5注解)</para> + + <para>请阅读JBoss EJB 3.0指南或者直接阅读Hibernate Annotations测试代码以获取更多的可运行实例.Hibernate Annotations提供的大部分单元测试代码都演示了实际的例子,是一个获取灵感的好地方.</para> + + <sect2> + <title>声明实体bean</title> + + <para>每一个持久化POJO类都是一个实体bean,这可以通过在类的定义中使用<literal>@Entity</literal>注解来进行声明:</para> + + <programlisting> +@Entity +public class Flight implements Serializable { + Long id; + + @Id + public Long getId() { return id; } + + public void setId(Long id) { this.id = id; } +} + </programlisting> + + <para>通过<literal>@Entity</literal>注解将一个类声明为一个实体bean(即一个持久化POJO类), + <literal>@Id</literal>注解则声明了该实体bean的标识属性. + 其他的映射定义是隐式的.这种以隐式映射为主体,以显式映射为例外的配置方式在新的EJ3规范中处于非常重要的位置, + 和以前的版本相比有了质的飞跃. + 在上面这段代码中:Flight类映射到Flight表,并使用id列作为主键列. + </para> + + <para>在对一个类进行注解时,你可以选择对它的的属性或者方法进行注解,根据你的选择,Hibernate的访问类型分别为 + <literal>field</literal>或<literal>property</literal>. + EJ3规范要求在需要访问的元素上进行注解声明,例如,如果访问类型为 + <literal>property</literal>就要在getter方法上进行注解声明, + 如果访问类型为 <literal>field</literal>就要在字段上进行注解声明.应该尽量避免混合使用这两种访问类型. + Hibernate根据<literal>@Id</literal> 或 <literal>@EmbeddedId</literal>的位置来判断访问类型.</para> + + <sect3> + <title>定义表(Table)</title> + + <para><literal>@Table</literal>是类一级的注解, + 通过<literal>@Table</literal>注解可以为实体bean映射指定表(table),目录(catalog)和schema的名字. + 如果没有定义<literal>@Table</literal>,那么系统自动使用默认值:实体的短类名(不附带包名).</para> + + <programlisting> +@Entity +@Table(name="tbl_sky") +public class Sky implements Serializable { +... + </programlisting> + + <para><literal>@Table</literal>元素包括了一个<literal>schema</literal> + 和一个 <literal>catalog</literal>属性,如果需要可以指定相应的值. + 结合使用<literal>@UniqueConstraint</literal>注解可以定义表的唯一约束(unique constraint) + (对于绑定到单列的唯一约束,请参考<literal>@Column</literal>注解) + </para> + + <programlisting>@Table(name="tbl_sky", + <emphasis role="bold">uniqueConstraints = {@UniqueConstraint(columnNames={"month", "day"})}</emphasis> + )</programlisting> + + <para>上面这个例子中,在month和day这两个字段上定义唯一约束. + 注意<literal>columnNames</literal>数组中的值指的是逻辑列名.</para> + + <remark>Hibernate在NamingStrategy的实现中定义了逻辑列名. + 默认的EJB3命名策略将物理字段名当作逻辑字段名来使用. + 注意该字段名和它对应的属性名可能不同(如果字段名是显式指定的话). + 除非你重写了NamingStrategy,否则不用担心这些区别..</remark> + </sect3> + + <sect3> + <title>乐观锁定版本控制</title> + + <para>你可以在实体bean中使用<literal>@Version</literal>注解,通过这种方式可添加对乐观锁定的支持:</para> + + <programlisting> +@Entity +public class Flight implements Serializable { +... + @Version + @Column(name="OPTLOCK") + public Integer getVersion() { ... } +} </programlisting> + + <para>上面这个例子中,version属性将映射到 <literal>OPTLOCK</literal>列, + entity manager使用该字段来检测更新冲突(防止更新丢失,请参考last-commit-wins策略).</para> + + <para>根据EJB3规范,version列可以是numeric类型(推荐方式)也可以是timestamp类型. + Hibernate支持任何自定义类型,只要该类型实现了<classname>UserVersionType</classname>.</para> + </sect3> + </sect2> + + <sect2> + <title>映射简单属性</title> + + <sect3> + <title>声明基本的属性映射</title> + + <para>Every non static non transient property (field or method) of an + entity bean is considered persistent, unless you annotate it as + <literal>@Transient</literal>. Not having an annotation for your + property is equivalent to the appropriate <literal>@Basic</literal> + annotation. The <literal>@Basic</literal> annotation allows you to + declare the fetching strategy for a property:</para> + + <para>实体bean中所有的非static非transient的属性都可以被持久化, + 除非你将其注解为<literal>@Transient</literal>.所有没有定义注解的属性等价于在其上面添加了@Basic注解. + 通过 <literal>@Basic</literal>注解可以声明属性的获取策略(fetch strategy):</para> + + <programlisting>public transient int counter; //transient property + +private String firstname; //persistent property + +@Transient +String getLengthInMeter() { ... } //transient property + +String getName() {... } // persistent property + +@Basic +int getLength() { ... } // persistent property + +@Basic(fetch = FetchType.LAZY) +String getDetailedComment() { ... } // persistent property + +@Temporal(TemporalType.TIME) +java.util.Date getDepartureTime() { ... } // persistent property + +@Enumerated(STRING) +Starred getNote() { ... } //enum persisted as String in database</programlisting> + + <para>上面这个例子中,<literal>counter</literal>是一个transient的字段, + <literal>lengthInMeter</literal>的getter方法被注解为<literal>@Transient</literal>, + entity manager将忽略这些字段和属性. + 而<literal>name</literal>,<literal>length</literal>,<literal>firstname</literal> + 这几个属性则是被定义为可持久化和可获取的.对于简单属性来说,默认的获取方式是即时获取(early fetch). + 当一个实体Bean的实例被创建时,Hibernate会将这些属性的值从数据库中提取出来,保存到Bean的属性里. + 与即时获取相对应的是延迟获取(lazy fetch).如果一个属性的获取方式是延迟获取 + (比如上面例子中的<literal>detailedComment</literal>属性), + Hibernate在创建一个实体Bean的实例时,不会即时将这个属性的值从数据库中读出. + 只有在该实体Bean的这个属性第一次被调用时,Hibernate才会去获取对应的值. + 通常你不需要对简单属性设置延迟获取(lazy simple property),千万不要和延迟关联获取(lazy association fetch)混淆了 + (译注:这里指不要把lazy simple property和lazy association fetch混淆了). + </para> + + <note> + <para>为了启用属性级的延迟获取,你的类必须经过特殊处理(instrumented): + 字节码将被织入原始类中来实现延迟获取功能, + 详情参考Hibernate参考文档.如果不对类文件进行字节码特殊处理, + 那么属性级的延迟获取将被忽略.</para> + </note> + + <para>推荐的替代方案是使用EJB-QL或者Criteria查询的投影(projection)功能.</para> + + <para>Hibernate和EJB3都支持所有基本类型的属性映射. + 这些基本类型包括所有的Java基本类型,及其各自的wrapper类和serializable类. + Hibernate Annotations还支持将内置的枚举类型映射到一个顺序列(保存了相应的序列值) + 或一个字符串类型的列(保存相应的字符串).默认是保存枚举的序列值, + 但是你可以通过<literal>@Enumerated</literal>注解来进行调整(见上面例子中的note属性).</para> + + <para>在核心的Java API中并没有定义时间精度(temporal precision). + 因此处理时间类型数据时,你还需要定义将其存储在数据库中所预期的精度. + 在数据库中,表示时间类型的数据有<literal>DATE</literal>, <literal>TIME</literal>, + 和 <literal>TIMESTAMP</literal>三种精度(即单纯的日期,时间,或者两者兼备). + 可使用<literal>@Temporal</literal>注解来调整精度.</para> + + <para><literal>@Lob</literal>注解表示属性将被持久化为Blob或者Clob类型, + 具体取决于属性的类型, + <classname>java.sql.Clob</classname>, + <classname>Character[]</classname>, + <classname>char[]</classname> 和 + <classname>java.lang.String</classname>这些类型的属性都被持久化为Clob类型, + 而<classname>java.sql.Blob</classname>, + <classname>Byte[]</classname>, + <classname>byte[]</classname> 和 + serializable类型则被持久化为Blob类型.</para> + + <programlisting> +@Lob +public String getFullText() { + return fullText; +} + +@Lob +public byte[] getFullCode() { + return fullCode; +} + </programlisting> + + <para>如果某个属性实现了<classname>java.io.Serializable</classname>同时也不是基本类型, + 并且没有在该属性上使用<literal>@Lob</literal>注解, + 那么Hibernate将使用自带的<literal>serializable</literal>类型. + </para> + </sect3> + + <sect3> + <title>声明列属性</title> + + <para>使用 <literal>@Column </literal>注解可将属性映射到列. + 使用该注解来覆盖默认值(关于默认值请参考EJB3规范). + 在属性级使用该注解的方式如下:</para> + + <itemizedlist> + <listitem> + <para>不进行注解</para> + </listitem> + + <listitem> + <para>和 <literal>@Basic</literal>一起使用</para> + </listitem> + + <listitem> + <para>和 <literal>@Version</literal>一起使用</para> + </listitem> + + <listitem> + <para>和 <literal>@Lob</literal>一起使用</para> + </listitem> + + <listitem> + <para>和 <literal>@Temporal</literal>一起使用</para> + </listitem> + + <listitem> + <para>和 + <literal>@org.hibernate.annotations.CollectionOfElements</literal>一起使用 + (只针对Hibernate )</para> + </listitem> + </itemizedlist> + + + <programlisting> +@Entity +public class Flight implements Serializable { +... +@Column(updatable = false, name = "flight_name", nullable = false, length=50) +public String getName() { ... } + </programlisting> + + <para>在上面这个例子中,<literal>name</literal>属性映射到<literal>flight_name</literal>列. + 该字段不允许为空,长度为50,并且是不可更新的(也就是属性值是不变的).</para> + + <para>上面这些注解可以被应用到正规属性上例如<literal>@Id</literal> 或<literal>@Version</literal>属性.</para> + + <programlistingco> + <areaspec> + <area coords="2 55" id="hm1" /> + + <area coords="3 55" id="hm2" /> + + <area coords="4 55" id="hm3" /> + + <area coords="5 55" id="hm4" /> + + <area coords="6 55" id="hm5" /> + + <area coords="7 55" id="hm6" /> + + <area coords="8 55" id="hm7" /> + + <area coords="9 55" id="hm8" /> + + <area coords="10 55" id="hm9" /> + + <area coords="11 55" id="hm10" /> + </areaspec> + + <programlisting>@Column( + name="columnName"; + boolean unique() default false; + boolean nullable() default true; + boolean insertable() default true; + boolean updatable() default true; + String columnDefinition() default ""; + String table() default ""; + int length() default 255; + int precision() default 0; // decimal precision + int scale() default 0; // decimal scale</programlisting> + + <calloutlist> + <callout arearefs="hm1"> + <para><literal>name</literal> 可选,列名(默认值是属性名)</para> + </callout> + + <callout arearefs="hm2"> + <para><literal>unique</literal> 可选,是否在该列上设置唯一约束(默认值false)</para> + </callout> + + <callout arearefs="hm3"> + <para><literal>nullable</literal> 可选,是否设置该列的值可以为空(默认值false)</para> + </callout> + + <callout arearefs="hm4"> + <para><literal>insertable</literal> 可选,该列是否作为生成的insert语句中的一个列(默认值true)</para> + </callout> + + <callout arearefs="hm5"> + <para><literal>updatable</literal> 可选,该列是否作为生成的update语句中的一个列(默认值true)</para> + </callout> + + <callout arearefs="hm6"> + <para><literal>columnDefinition</literal> 可选: 为这个特定列覆盖SQL DDL片段 (这可能导致无法在不同数据库间移植)</para> + </callout> + + <callout arearefs="hm7"> + <para><literal>table</literal> 可选,定义对应的表(默认为主表)</para> + </callout> + + <callout arearefs="hm8"> + <para><literal><literal>length</literal></literal> 可选,列长度(默认值255)</para> + </callout> + + <callout arearefs="hm8"> + <para><literal><literal>precision</literal></literal> + 可选,列十进制精度(decimal precision)(默认值0)</para> + </callout> + + <callout arearefs="hm10"> + <para><literal><literal>scale</literal></literal> + 可选,如果列十进制数值范围(decimal scale)可用,在此设置(默认值0)</para> + </callout> + </calloutlist> + </programlistingco> + </sect3> + + <sect3> + <title>嵌入式对象(又名组件)</title> + + <para>在实体中可以定义一个嵌入式组件(embedded component), + 甚至覆盖该实体中原有的列映射. + 组件类必须在类一级定义<literal>@Embeddable</literal>注解. + 在特定的实体的关联属性上使用<literal>@Embedded</literal>和 + <literal>@AttributeOverride</literal>注解可以覆盖该属性对应的嵌入式对象的列映射:</para> + + <programlisting> +@Entity +public class Person implements Serializable { + + // Persistent component using defaults + Address homeAddress; + + @Embedded + @AttributeOverrides( { + @AttributeOverride(name="iso2", column = @Column(name="bornIso2") ), + @AttributeOverride(name="name", column = @Column(name="bornCountryName") ) + } ) + Country bornIn; + ... +} + </programlisting> + + <programlisting> +@Embeddable +public class Address implements Serializable { + String city; + Country nationality; //no overriding here +} + </programlisting> + + <programlisting> +@Embeddable +public class Country implements Serializable { + private String iso2; + @Column(name="countryName") private String name; + + public String getIso2() { return iso2; } + public void setIso2(String iso2) { this.iso2 = iso2; } + + + public String getName() { return name; } + public void setName(String name) { this.name = name; } + ... +} + </programlisting> + + <para>嵌入式对象继承其所属实体中定义的访问类型 + (注意:这可以通过使用Hibernate提供的<literal>@AccessType</literal>注解来覆盖原有值)(请参考 <xref + linkend="entity-hibspec" />).</para> + + <para>在上面的例子中,实体bean <literal>Person</literal> 有两个组件属性, + 分别是<literal>homeAddress</literal>和<literal>bornIn</literal>. + 我们可以看到<literal>homeAddress</literal> 属性并没有注解. + 但是Hibernate自动检测其对应的Address类中的<literal>@Embeddable</literal>注解, + 并将其看作一个持久化组件.对于Country中已映射的属性, + 则使用<literal>@Embedded</literal>和<literal>@AttributeOverride + </literal>注解来覆盖原来映射的列名. + 正如你所看到的, <literal>Address</literal>对象中还内嵌了<literal>Country</literal>对象, + 这里和<literal>homeAddress</literal>一样使用了Hibernate和EJB3自动检测机制. + 目前EJB3规范还不支持覆盖多层嵌套(即嵌入式对象中还包括其他嵌入式对象)的列映射. + 不过Hibernate通过在表达式中使用"."符号表达式提供了对此特征的支持.</para> + + <para><programlisting> @Embedded + @AttributeOverrides( { + @AttributeOverride(name="city", column = @Column(name="fld_city") ) + @AttributeOverride(name="<emphasis role="bold">nationality.iso2</emphasis>", column = @Column(name="nat_Iso2") ), + @AttributeOverride(name="<emphasis role="bold">nationality.name</emphasis>", column = @Column(name="nat_CountryName") ) + //nationality columns in homeAddress are overridden + } ) + Address homeAddress;</programlisting> + Hibernate注解支持很多EJB3规范中没有明确定义的特性. + 例如,可以在嵌入式对象上添加 <literal>@MappedSuperclass</literal>注解, + 这样可以将其父类的属性持久(详情请查阅<literal>@MappedSuperclass</literal>).</para> + + <para>Hibernate现在支持在嵌入式对象中使用关联注解(如<literal>@*ToOne</literal>和<literal>@*ToMany</literal>). + 而EJB3规范尚不支持这样的用法。你可以使用 <literal>@AssociationOverride</literal>注解来覆写关联列.</para> + + + <para>在同一个实体中使用两个同类型的嵌入对象, + 其默认列名是无效的:至少要对其中一个进行明确声明. + Hibernate在这方面走在了EJB3规范的前面, + Hibernate提供了<classname>NamingStrategy</classname>, 在使用Hibernate时, + 通过<classname>NamingStrategy</classname>你可以对默认的机制进行扩展. + <classname>DefaultComponentSafeNamingStrategy</classname> + 在默认的EJB3NamingStrategy上进行了小小的提升, + 允许在同一实体中使用两个同类型的嵌入对象而无须额外的声明.</para> + + </sect3> + + <sect3> + <title>无注解之属性的默认值</title> + + <para>如果某属性没有注解,该属性将遵守下面的规则:</para> + + <itemizedlist> + <listitem> + 如果属性为单一类型,则映射为@Basic + </listitem> + + <listitem> + 否则,如果属性对应的类型定义了@Embeddable注解,则映射为@Embedded + </listitem> + + <listitem> + 否则,如果属性对应的类型实现了Serializable, + 则属性被映射为@Basic并在一个列中保存该对象的serialized版本 + </listitem> + + <listitem> + 否则,如果该属性的类型为java.sql.Clob 或 java.sql.Blob,则作为@Lob并映射到适当的LobType. + </listitem> + </itemizedlist> + + </sect3> + </sect2> + + <sect2 id="mapping-identifier" label="" + xreflabel="Mapping identifier properties"> + <title>映射主键属性</title> + + <para>使用<literal>@Id</literal>注解可以将实体bean中的某个属性定义为标识符(identifier). + 该属性的值可以通过应用自身进行设置, + 也可以通过Hiberante生成(推荐). + 使用 <literal>@GeneratedValue</literal>注解可以定义该标识符的生成策略: + </para> + + <itemizedlist> + <listitem> + AUTO - 可以是identity column类型,或者sequence类型或者table类型,取决于不同的底层数据库. + </listitem> + + <listitem> + TABLE - 使用表保存id值 + </listitem> + + <listitem> + IDENTITY - identity column + </listitem> + + <listitem> + SEQUENCE - sequence + </listitem> + </itemizedlist> + + <para>和EJB3规范相比,Hibernate提供了更多的id生成器.详情请查阅 <xref linkend="entity-hibspec" /> .</para> + + + <para>下面的例子展示了使用SEQ_STORE配置的sequence生成器</para> + + <programlisting> +@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE") +public Integer getId() { ... } + </programlisting> + + <para>下面这个例子使用的是identity生成器</para> + + <programlisting> +@Id @GeneratedValue(strategy=GenerationType.IDENTITY) +public Long getId() { ... } + </programlisting> + + <para><literal>AUTO</literal>生成器适用于可移植的应用(在多个DB间切换). + 多个<literal>@Id</literal>可以共享同一个identifier生成器,只要把generator属性设成相同的值就可以了. + 通过<literal>@SequenceGenerator</literal> 和<literal>@TableGenerator</literal>,你可以配置不同的identifier生成器. + 每一个identifier生成器都有自己的适用范围,可以是应用级(application level)和类一级(class level). + 类一级的生成器在外部是不可见的, + 而且类一级的生成器可以覆盖应用级的生成器. + 应用级的生成器则定义在包一级(package level)(如<classname>package-info.java</classname>):</para> + + <programlisting> +...@ja...rsistence.TableGenerator( + name="EMP_GEN", + table="GENERATOR_TABLE", + pkColumnName = "key", + valueColumnName = "hi" + pkColumnValue="EMP", + allocationSize=20 +) +...@ja...quenceGenerator( + name="SEQ_GEN", + sequenceName="my_sequence" +) +package org.hibernate.test.metadata; + </programlisting> + + <para> + 如果在<classname>org.hibernate.test.metadata</classname>包下面的 + <classname>package-info.java</classname>文件用于初始化EJB配置, + 那么该文件中定义的 <literal>EMP_GEN</literal> + 和<literal>SEQ_GEN</literal>都是应用级的生成器. + <literal>EMP_GEN</literal>定义了一个使用hilo算法 + (max_lo为20)的id生成器(该生成器将id的信息存在数据库的某个表中.). + id的hi值保存在<literal>GENERATOR_TABLE</literal>中. + 在该表中 <literal>pkColumnName</literal>"key"等价于 + <literal>pkColumnValue</literal> "<literal>EMP</literal>", + 而<literal>valueColumnName</literal> "<literal>hi</literal>"中存储的是下一个要使用的最大值. + </para> + + <para><literal>SEQ_GEN</literal>则定义了一个sequence 生成器, + 其对应的sequence名为 <literal>my_sequence</literal>. + 注意目前Hibernate Annotations还不支持sequence 生成器中的 + <literal>initialValue</literal>和 <literal>allocationSize</literal>参数.</para> + + <para>下面这个例子展示了定义在类范围(class scope)的sequence生成器:</para> + + <programlisting> +@Entity +...@ja...quenceGenerator( + name="SEQ_STORE", + sequenceName="my_sequence" +) +public class Store implements Serializable { + private Long id; + + @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE") + public Long getId() { return id; } +} + </programlisting> + + <para>在这个例子中,Store类使用名为my_sequence的sequence,并且SEQ_STORE 生成器对于其他类是不可见的. + 注意在org.hibernate.test.metadata.id包下的测试代码有更多演示Hibernate Annotations用法的例子..</para> + + <para>下面是定义组合主键的几种语法:</para> + + <itemizedlist> + <listitem> + 将组件类注解为@Embeddable,并将组件的属性注解为@Id + </listitem> + + <listitem> + 将组件的属性注解为@EmbeddedId + </listitem> + + <listitem> + 将类注解为@IdClass,并将该实体中所有属于主键的属性都注解为@Id + </listitem> + </itemizedlist> + + <para>对于EJB2的开发人员来说 <literal>@IdClass</literal>是很常见的, + 但是对于Hibernate的用户来说就是一个崭新的用法. + 组合主键类对应了一个实体类中的多个字段或属性, + 而且主键类中用于定义主键的字段或属性和 + 实体类中对应的字段或属性在类型上必须一致.下面我们看一个例子:</para> + + <programlisting>@Entity +<emphasis role="bold">@IdClass(FootballerPk.class)</emphasis> +public class Footballer { + //part of the id key + <emphasis role="bold">@Id</emphasis> public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + //part of the id key + <emphasis role="bold">@Id</emphasis> public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public String getClub() { + return club; + } + + public void setClub(String club) { + this.club = club; + } + + //appropriate equals() and hashCode() implementation +} + +@Embeddable +public class FootballerPk implements Serializable { + //same name and type as in Footballer + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + //same name and type as in Footballer + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + //appropriate equals() and hashCode() implementation +} +</programlisting> + + + <para>如上, <literal>@IdClass</literal>指向对应的主键类.</para> + + <para>Hibernate支持在组合标识符中定义关联(就像使用普通的注解一样),而EJB3规范并不支持此类用法. + </para> + + <programlisting>@Entity +@AssociationOverride( name="id.channel", joinColumns = @JoinColumn(name="chan_id") ) +public class TvMagazin { + @EmbeddedId public TvMagazinPk id; + @Temporal(TemporalType.TIME) Date time; +} + +@Embeddable +public class TvMagazinPk implements Serializable { + @ManyToOne + public Channel channel; + public String name; + @ManyToOne + public Presenter presenter; +} +</programlisting> + + </sect2> + + <sect2> + <title>映射继承关系</title> + + <para>EJB3支持三种类型的继承映射:</para> + + <itemizedlist> + <listitem> + 每个类一张表(Table per class)策略: 在Hibernate中对应<union-class>元素: + </listitem> + + <listitem> + 每个类层次结构一张表(Single table per class hierarchy)策略:在Hibernate中对应<subclass>元素 + </listitem> + + <listitem> + 连接的子类(Joined subclasses)策略:在Hibernate中对应 <joined-subclass>元素 + </listitem> + </itemizedlist> + + <para> + 你可以用 <literal>@Inheritance</literal>注解来定义所选择的策略. + 这个注解需要在每个类层次结构(class hierarchy) 最顶端的实体类上使用. + </para> + + <note> + <para>目前还不支持在接口上进行注解.</para> + </note> + + <sect3> + <title>每个类一张表</title> + + <para> + 这种策略有很多缺点(例如:多态查询和关联),EJB3规范, Hibernate参考手册, + Hibernate in Action,以及其他许多地方都对此进行了描述和解释. + Hibernate使用<literal>SQL UNION</literal>查询来实现这种策略. + 通常使用场合是在一个继承层次结构的顶端:</para> + + <programlisting> +@Entity +@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) +public class Flight implements Serializable { + </programlisting> + + <para> + 这种策略支持双向的一对多关联. + 这里不支持<literal>IDENTITY</literal>生成器策略,因为id必须在多个表间共享. + 当然,一旦使用这种策略就意味着你不能使用 + <literal>AUTO </literal>生成器和<literal>IDENTITY</literal>生成器. + </para> + </sect3> + + <sect3> + <title>每个类层次结构一张表</title> + + <para>整个继承层次结构中的父类和子类的所有属性都映射到同一个表中, + 他们的实例通过一个辨别符(discriminator)列来区分.:</para> + + <programlisting> +@Entity +@Inheritance(strategy=InheritanceType.SINGLE_TABLE) +@DiscriminatorColumn( + name="planetype", + discriminatorType=DiscriminatorType.STRING +) +@DiscriminatorValue("Plane") +public class Plane { ... } + +@Entity +@DiscriminatorValue("A320") +public class A320 extends Plane { ... } + </programlisting> + + <para>在上面这个例子中,<classname>Plane</classname>是父类,在这个类里面将继承策略定义为 + <literal>InheritanceType.SINGLE_TABLE</literal>,并通过 + <literal>@DiscriminatorColumn</literal>注解定义了辨别符列(还可以定义辨别符的类型). + 最后,对于继承层次结构中的每个类,<literal>@DiscriminatorValue</literal>注解指定了用来辨别该类的值. + 辨别符列的名字默认为 <literal>DTYPE</literal>,其默认值为实体名(在<literal>@Entity.name</literal>中定义),其类型 + 为DiscriminatorType.STRING. + <classname>A320</classname>是子类,如果不想使用默认的辨别符,只需要指定相应的值即可. + 其他的如继承策略,辨别标志字段的类型都是自动设定的.</para> + + <para><literal>@Inheritance</literal> 和 + <literal>@DiscriminatorColumn</literal> 注解只能用于实体层次结构的顶端.</para> + + </sect3> + + <sect3> + <title>连接的子类</title> + + <para>当每个子类映射到一个表时, <literal> @PrimaryKeyJoinColumn</literal> + 和<literal>@PrimaryKeyJoinColumns</literal> + 注解定义了每个子类表关联到父类表的主键:</para> + + <programlisting> +@Entity +@Inheritance(strategy=InheritanceType.JOINED) +public class Boat implements Serializable { ... } + +@Entity +public class Ferry extends Boat { ... } + +@Entity +@PrimaryKeyJoinColumn(name="BOAT_ID") +public class AmericaCupClass extends Boat { ... } + </programlisting> + + <para>以上所有实体都使用了<literal>JOINED</literal>策略, + <literal>Ferry</literal>表和<literal>Boat</literal>表使用同名的主键. + 而<literal>AmericaCupClass</literal>表和<literal>Boat</literal>表使用了条件 + <code>Boat.id = AmericaCupClass.BOAT_ID</code>进行关联. + </para> + </sect3> + + <sect3> + <title>从父类继承的属性</title> + + <para>有时候通过一个(技术上或业务上)父类共享一些公共属性是很有用的, + 同时还不用将该父类作为映射的实体(也就是该实体没有对应的表). + 这个时候你需要使用<literal>@MappedSuperclass</literal>注解来进行映射.</para> + + <programlisting>@MappedSuperclass +public class BaseEntity { + @Basic + @Temporal(TemporalType.TIMESTAMP) + public Date getLastUpdate() { ... } + public String getLastUpdater() { ... } + ... +} + +@Entity class Order extends BaseEntity { + @Id public Integer getId() { ... } + ... +}</programlisting> + + <para>在数据库中,上面这个例子中的继承的层次结构最终以<literal>Order</literal>表的形式出现, + 该表拥有<literal>id</literal>, <literal>lastUpdate</literal> 和 + <literal>lastUpdater</literal>三个列.父类中的属性映射将复制到其子类实体. + 注意这种情况下的父类不再处在继承层次结构的顶端.</para> + + <note> + + <para>注意,没有注解为<literal>@MappedSuperclass</literal>的父类中的属性将被忽略.</para> + </note> + + <note> + + <para>除非显式使用Hibernate annotation中的<literal>@AccessType</literal>注解, + 否则将从继承层次结构的根实体中继承访问类型(包括字段或方法)</para> + </note> + + <note> + + <para>这对于<literal>@Embeddable</literal>对象的父类中的属性持久化同样有效. + 只需要使用<literal>@MappedSuperclass</literal>注解即可 + (虽然这种方式不会纳入EJB3标准)</para> + + </note> + + <note> + + <para>可以将处在在映射继承层次结构的中间位置的类注解为<literal>@MappedSuperclass</literal>.</para> + </note> + + <note> + + <para>在继承层次结构中任何没有被注解为<literal>@MappedSuperclass</literal> + 或<literal>@Entity</literal>的类都将被忽略.</para> + </note> + + <para> + 你可以通过 <literal>@AttributeOverride</literal>注解覆盖实体父类中的定义的列. + 这个注解只能在继承层次结构的顶端使用.</para> + + <programlisting>@MappedSuperclass +public class FlyingObject implements Serializable { + + public int getAltitude() { + return altitude; + } + + @Transient + public int getMetricAltitude() { + return metricAltitude; + } + + @ManyToOne + public PropulsionType getPropulsion() { + return metricAltitude; + } + ... +} + +@Entity +@AttributeOverride( name="altitude", column = @Column(name="fld_altitude") ) +@AssociationOverride( name="propulsion", joinColumns = @JoinColumn(name="fld_propulsion_fk") ) +public class Plane extends FlyingObject { + ... +}</programlisting> + + <para>在上面这个例子中,<literal>altitude</literal>属性的值最终将持久化到<literal>Plane</literal> + 表的<literal>fld_altitude</literal>列.而名为propulsion的关联则保存在<literal>fld_propulsion_fk</literal>外间列.</para> + + <para>你可以为<literal>@Entity</literal>和<literal>@MappedSuperclass</literal>注解的类 + 以及那些对象为<literal>@Embeddable</literal>的属性定义 + <literal>@AttributeOverride</literal>和<literal>@AssociationOverride</literal>.</para> + + </sect3> + </sect2> + + <sect2 id="entity-mapping-association"> + <title>映射实体Bean的关联关系</title> + + <sect3> + <title>一对一(One-to-one)</title> + + <para>使用<literal>@OneToOne</literal>注解可以建立实体bean之间的一对一的关联. + 一对一关联有三种情况: + 一是关联的实体都共享同样的主键, + 二是其中一个实体通过外键关联到另一个实体的主键 + (注意要模拟一对一关联必须在外键列上添加唯一约束). + 三是通过关联表来保存两个实体之间的连接关系 + (注意要模拟一对一关联必须在每一个外键上添加唯一约束).</para> + + <para>首先,我们通过共享主键来进行一对一关联映射:</para> + + <programlisting> +@Entity +public class Body { + @Id + public Long getId() { return id; } + + @OneToOne(cascade = CascadeType.ALL) + @PrimaryKeyJoinColumn + public Heart getHeart() { + return heart; + } + ... +} + </programlisting> + + <programlisting> +@Entity +public class Heart { + @Id + public Long getId() { ...} +} + </programlisting> + + <para>上面的例子通过使用注解<literal>@PrimaryKeyJoinColumn</literal>定义了一对一关联.</para> + + <para>下面这个例子使用外键列进行实体的关联.</para> + + <programlisting> +@Entity +public class Customer implements Serializable { + @OneToOne(cascade = CascadeType.ALL) + <emphasis role="bold">@JoinColumn(name="passport_fk")</emphasis> + public Passport getPassport() { + ... + } + +@Entity +public class Passport implements Serializable { + @OneToOne(<emphasis role="bold">mappedBy = "passport"</emphasis>) + public Customer getOwner() { + ... +} + </programlisting> + + <para>上面这个例子中,<classname>Customer</classname> 通过<literal>Customer</literal> + 表中名为的<literal>passport_fk</literal> 外键列和 <classname>Passport</classname>关联. + <literal>@JoinColumn</literal>注解定义了联接列(join column). + 该注解和<literal>@Column</literal>注解有点类似, + 但是多了一个名为<literal>referencedColumnName</literal>的参数. + 该参数定义了所关联目标实体中的联接列. + 注意,当<literal><literal>referencedColumnName</literal></literal>关联到非主键列的时候, + 关联的目标类必须实现<classname>Serializable</classname>, + 还要注意的是所映射的属性对应单个列(否则映射无效). + </para> + + <para>一对一关联可能是双向的.在双向关联中, + 有且仅有一端是作为主体(owner)端存在的:主体端负责维护联接列(即更新). + 对于不需要维护这种关系的从表则通过mappedBy属性进行声明. + <literal>mappedBy</literal>的值指向主体的关联属性. + 在上面这个例子中,<literal>mappedBy</literal>的值为 <literal>passport</literal>. + 最后,不必也不能再在被关联端(owned side)定义联接列了,因为已经在主体端进行了声明.</para> + + <para>如果在主体没有声明<literal>@JoinColumn</literal>,系统自动进行处理: + 在主表(owner table)中将创建联接列, + 列名为:主体的关联属性名+下划线+被关联端的主键列名. + 在上面这个例子中是<literal>passport_id</literal>, + 因为<literal>Customer</literal>中关联属性名为<literal>passport</literal>, + <literal>Passport</literal>的主键是<literal>id</literal>.</para> + + <para>The third possibility (using an association table) is very + exotic.</para> + + <para>第三种方式也许是最另类的(通过关联表).</para> + + <programlisting> +@Entity +public class Customer implements Serializable { + @OneToOne(cascade = CascadeType.ALL) + <emphasis role="bold">@JoinTable(name = "CustomerPassports" + joinColumns = @JoinColumn(name="customer_fk"), + inverseJoinColumns = @JoinColumns(name="passport_fk")</emphasis> + ) + public Passport getPassport() { + ... + } + +@Entity +public class Passport implements Serializable { + @OneToOne(<emphasis role="bold">mappedBy = "passport"</emphasis>) + public Customer getOwner() { + ... +} + </programlisting> + + <para><classname>Customer</classname>通过名为 <literal>CustomerPassports</literal>的关联表和 + <classname>Passport</classname>关联; 该关联表拥有名为<literal>passport_fk</literal>的外键列,该 + 外键指向<literal>Passport</literal>表,该信息定义为<literal>inverseJoinColumn</literal>的属性值, + 而<literal>customer_fk</literal>外键列指向<literal>Customer</literal>表, + 该信息定义为 <literal>joinColumns</literal>的属性值.</para> + + <para>这种关联可能是双向的.在双向关联中, + 有且仅有一端是作为主体端存在的:主体端负责维护联接列(即更新). + 对于不需要维护这种关系的从表则通过mappedBy属性进行声明. + <literal>mappedBy</literal>的值指向主体的关联属性. + 在上面这个例子中,<literal>mappedBy</literal>的值为 <literal>passport</literal>. + 最后,不必也不能再在被关联端(owned side)定义联接列了,因为已经在主体端进行了声明.</para> + + <para>你必须明确定义关联表名和关联列名.</para> + + </sect3> + + <sect3> + <title>多对一(Many-to-one)</title> + + <para>在实体属性一级使用<literal>@ManyToOne</literal>注解来定义多对一关联:</para> + + <programlisting> +@Entity() +public class Flight implements Serializable { + <emphasis role="bold">@ManyToOne</emphasis>( cascade = {CascadeType.PERSIST, CascadeType.MERGE} ) + @JoinColumn(name="COMP_ID") + public Company getCompany() { + return company; + } + ... +} + </programlisting> + + <para>其中<literal>@JoinColumn</literal>是可选的,关联字段默认值和一对一 + (one to one)关联的情况相似, + 列名为:主体的关联属性名+下划线+被关联端的主键列名. + 在这个例子中是<literal>company_id</literal>, + 因为关联的属性是<literal>company</literal>, + <literal>Company</literal>的主键是<literal>id</literal>.</para> + + <para><literal>@ManyToOne</literal>注解有一个名为<literal>targetEntity</literal>的参数, + 该参数定义了目标实体名.通常不需要定义该参数, + 因为在大部分情况下默认值(表示关联关系的属性类型)就可以很好的满足要求了. + 不过下面这种情况下这个参数就显得有意义了:使用接口作为返回值而不是常见的实体.</para> + + <programlisting> +@Entity() +public class Flight implements Serializable { + @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, <emphasis + role="bold">targetEntity=CompanyImpl.class</emphasis> ) + @JoinColumn(name="COMP_ID") + public Company getCompany() { + return company; + } + ... +} + +public interface Company { + ... + </programlisting> + + <para>对于多对一也可以通过关联表的方式来映射。 + 通过<literal>@JoinTable</literal>注解可定义关联表, + 该关联表包含了指回实体表的外键(通过<literal>@JoinTable.joinColumns</literal>) + 以及指向目标实体表的外键(通过<literal>@JoinTable.inverseJoinColumns</literal>).</para> + + <programlisting> +@Entity() +public class Flight implements Serializable { + @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} ) + <emphasis role="bold">@JoinTable(name="Flight_Company", + joinColumns = @JoinColumn(name="FLIGHT_ID"), + inverseJoinColumns = @JoinColumns(name="COMP_ID") + )</emphasis> + public Company getCompany() { + return company; + } + ... +} + </programlisting> + </sect3> + + <sect3 id="entity-mapping-association-collections"> + <title>集合类型</title> + + <sect4> + <title>概况</title> + + <para>你可以对 <classname>Collection </classname>,<literal>List</literal> + (指有序列表, 而不是索引列表), + <literal>Map</literal>和<classname>Set</classname>这几种类型进行映射. + EJB3规范定义了怎么样使用<literal>@javax.persistence.OrderBy</literal> + 注解来对有序列表进行映射: + 该注解接受的参数格式:用逗号隔开的(目标实体)属性名及排序指令, + 如<code>firstname asc, age desc</code>,如果该参数为空,则默认以id对该集合进行排序. + 如果某个集合在数据库中对应一个关联表(association table)的话,你不能在这个集合属性上面使用@OrderBy注解. + 对于这种情况的处理方法,请参考<xref linkend="entity-hibspec" />. + EJB3 允许你利用目标实体的一个属性作为Map的key, + 这个属性可以用<literal>@MapKey(name="myProperty")</literal>来声明. + 如果使用<literal>@MapKey</literal>注解的时候不提供属性名, + 系统默认使用目标实体的主键. + map的key使用和属性相同的列:不需要为map key定义专用的列,因为map key实际上就表达了一个目标属性。 + 注意一旦加载,key不再和属性保持同步, + 也就是说,如果你改变了该属性的值,在你的Java模型中的key不会自动更新 + (请参考<xref linkend="entity-hibspec" />). + 很多人被<literal><map></literal>和<literal>@MapKey</literal>弄糊涂了。 + 其他它们有两点区别.<literal>@MapKey</literal>目前还有一些限制,详情请查看论坛或者 + 我们的JIRA缺陷系统。 + + + 注意一旦加载,key不再和属性保持同步, + 也就是说,如果你改变了该属性的值,在你的Java模型中的key不会自动更新. + (Hibernate 3中Map支持的方式在当前的发布版中还未得到支持).</para> + + <para>Hibernate将集合分以下几类.</para> + + <para></para> + + <table> + <title>集合语义</title> + + <tgroup cols="3"> + <colspec colname="c1" /> + + <colspec colname="c2" /> + + <colspec colname="c3" colnum="2" /> + + <thead> + <row> + <entry>语义</entry> + + <entry>Java实现类</entry> + + <entry> 注解</entry> + </row> + </thead> + + <tbody> + <row> + <entry>Bag 语义</entry> + + <entry>java.util.List, java.util.Collection</entry> + + <entry>@org.hibernate.annotations.CollectionOfElements 或 + @OneToMany 或 @ManyToMany</entry> + </row> + + <row> + <entry>List 语义</entry> + + <entry>java.util.List</entry> + + <entry>(@org.hibernate.annotations.CollectionOfElements 或 + @OneToMany 或 @ManyToMany) + 以及 + @org.hibernate.annotations.IndexColumn</entry> + </row> + + <row> + <entry>Set 语义</entry> + + <entry>java.util.Set</entry> + + <entry>@org.hibernate.annotations.CollectionOfElements 或 + @OneToMany 或 @ManyToMany</entry> + </row> + + <row> + <entry>Map 语义</entry> + + <entry>java.util.Map</entry> + + <entry>(@org.hibernate.annotations.CollectionOfElements 或 + @OneToMany 或 @ManyToMany) + 以及 + (空 + 或 + @org.hibernate.annotations.MapKey/MapKeyManyToMany(支持真正的map), + 或 + @javax.persistence.MapKey</entry> + + </row> + </tbody> + </tgroup> + </table> + + <remark> + 从上面可以明确地看到,没有@org.hibernate.annotations.IndexColumn + 注解的java.util.List集合将被看作bag类. + </remark> + + <para>EJB3规范不支持原始类型,核心类型,嵌入式对象的集合.但是Hibernate对此提供了支持 + (详情参考 <xref linkend="entity-hibspec" />).</para> + + <programlisting>@Entity public class City { + @OneToMany(mappedBy="city") + <emphasis role="bold">@OrderBy("streetName")</emphasis> + public List<Street> getStreets() { + return streets; + } +... +} + +@Entity public class Street { + <emphasis role="bold">public String getStreetName()</emphasis> { + return streetName; + } + + @ManyToOne + public City getCity() { + return city; + } + ... +} + + +@Entity +public class Software { + @OneToMany(mappedBy="software") + <emphasis role="bold">@MapKey(name="codeName")</emphasis> + public Map<String, Version> getVersions() { + return versions; + } +... +} + +@Entity +@Table(name="tbl_version") +public class Version { + <emphasis role="bold">public String getCodeName()</emphasis> {...} + + @ManyToOne + public Software getSoftware() { ... } +... +}</programlisting> + + <para>上面这个例子中,<literal>City</literal> + 中包括了以<literal>streetName</literal>排序的<literal>Street</literal>的集合. + 而<literal>Software</literal>中包括了以<literal>codeName</literal>作为 + key和以<literal>Version</literal>作为值的Map.</para> + + <para>除非集合为generic类型,否则你需要指定<literal>targetEntity</literal>. + 这个注解属性接受的参数为目标实体的class.</para> + </sect4> + + <sect4 id="entity-mapping-association-collection-onetomany" + revision="2"> + <title>一对多(One-to-many)</title> + + <para>在属性级使用 <literal>@OneToMany</literal>注解可定义一对多关联.一对多关联可以是双向关联.</para> + + <sect5> + <title>双向(Bidirectional)</title> + + <para>在EJB3规范中多对一这端几乎总是双向关联中的主体(owner)端, + 而一对多这端的关联注解为<literal>@OneToMany( mappedBy=... + )</literal></para> + + <programlisting>@Entity +public class Troop { + @OneToMany(mappedBy="troop") + public Set<Soldier> getSoldiers() { + ... +} + +@Entity +public class Soldier { + @ManyToOne + @JoinColumn(name="troop_fk") + public Troop getTroop() { + ... +} </programlisting> + + <para><classname>Troop</classname> 通过<literal>troop</literal> + 属性和<literal>Soldier</literal>建立了一对多的双向关联. + 在<literal>mappedBy</literal>端不必也不能再定义任何物理映射</para> + + <para>对于一对多的双向映射,如果要一对多这一端维护关联关系, + 你需要删除<literal>mappedBy</literal>元素并将多对一这端的 + <literal>@JoinColumn</literal>的insertable和updatable设置为false. + 很明显,这种方案不会得到什么明显的优化,而且还会增加一些附加的UPDATE语句.</para> + + <programlisting>@Entity +public class Troop { + @OneToMany + @JoinColumn(name="troop_fk") //we need to duplicate the physical information + public Set<Soldier> getSoldiers() { + ... +} + +@Entity +public class Soldier { + @ManyToOne + @JoinColumn(name="troop_fk", insertable=false, updatable=false) + public Troop getTroop() { + ... +}</programlisting> + </sect5> + + <sect5> + <title>单向(Unidirectional)</title> + + <para>通过在被拥有的实体端(owned entity)增加一个外键列来实现一对多单向关联是很少见的,也是不推荐的. + 我们强烈建议通过一个联接表(join table)来实现这种关联(下一节会对此进行解释). + 可以通过<literal>@JoinColumn</literal>注解来描述这种单向关联关系.</para> + + <programlisting> +@Entity +public class Customer implements Serializable { + @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) + @JoinColumn(name="CUST_ID") + public Set<Ticket> getTickets() { + ... +} + +@Entity +public class Ticket implements Serializable { + ... //no bidir +} + </programlisting> + + <para><literal>Customer</literal> 通过 + <literal>CUST_ID</literal>列和<literal>Ticket</literal> 建立了单向关联关系.</para> + + </sect5> + + <sect5> + <title>通过关联表处理单向关联</title> + + <para>通过联接表处理单向一对多关联是首选方式.这种关联通过<literal>@JoinTable</literal>注解来进行描述.</para> + + <programlisting> +@Entity +public class Trainer { + @OneToMany + @JoinTable( + name="TrainedMonkeys", + joinColumns = { @JoinColumn( name="trainer_id") }, + inverseJoinColumns = @JoinColumn( name="monkey_id") + ) + public Set<Monkey> getTrainedMonkeys() { + ... +} + +@Entity +public class Monkey { + ... //no bidir +} + </programlisting> + + <para>上面这个例子中,<literal>Trainer</literal>通过 + <classname>TrainedMonkeys</classname>表和 + <classname>Monkey</classname> 建立了单向关联. + 其中外键<literal>trainer_id</literal>关联到<literal>Trainer</literal> + (<literal>joinColumns</literal>), + 而外键<literal>monkey_id</literal>关联到 <literal>Monkey</literal> + (<literal>inversejoinColumns</literal>).</para> + </sect5> + + <sect5> + <title>默认处理机制</title> + + <para>通过联接表来建立单向一对多关联不需要描述任何物理映射. + 表名由以下三个部分组成:主表(owner table)表名+下划线+从表(the other side table)表名. + 指向主表的外键名:主表表名+下划线+主表主键列名 + 指向从表的外键名:主表所对应实体的属性名+下划线+从表主键列名 + 指向从表的外键定义为唯一约束,用来表示一对多的关联关系.</para> + + <programlisting> +@Entity +public class Trainer { + @OneToMany + public Set<Tiger> getTrainedTigers() { + ... +} + +@Entity +public class Tiger { + ... //no bidir +} + </programlisting> + + <para>上面这个例子中,<classname>Trainer</classname>和<classname>Tiger</classname> + 通过联接表 <literal>Trainer_Tiger</literal>建立单向关联关系, + 其中外键<literal>trainer_id</literal>关联到<literal>Trainer</literal> + (主表表名, <keycap>_</keycap>(下划线), trainer id), + 而外键<literal>trainedTigers_id</literal>关联到<literal>Tiger</literal> + (属性名称, <keycap>_</keycap>(下划线), Tiger表的主键列名).</para> + + </sect5> + </sect4> + + <sect4> + <title>多对多(Many-to-many)</title> + + <sect5> + <title>定义</title> + + <para>你可以通过<literal>@ManyToMany</literal>注解可定义的多对多关联. + 同时,你也需要通过注解<literal>@JoinTable</literal>描述关联表和关联条件. + 如果是双向关联,其中一段必须定义为owner,另一端必须定义为inverse(在对关联表进行更新操作时这一端将被忽略):</para> + + <programlisting> +@Entity +public class Employer implements Serializable { + @ManyToMany( + targetEntity=org.hibernate.test.metadata.manytomany.Employee.class, + cascade={CascadeType.PERSIST, CascadeType.MERGE} + ) + @JoinTable( + name="EMPLOYER_EMPLOYEE", + joinColumns={@JoinColumn(name="EMPER_ID")}, + inverseJoinColumns={@JoinColumn(name="EMPEE_ID")} + ) + public Collection getEmployees() { + return employees; + } + ... +} + </programlisting> + + <programlisting> +@Entity +public class Employee implements Serializable { + @ManyToMany( + cascade={CascadeType.PERSIST, CascadeType.MERGE}, + mappedBy="employees" + targetEntity=Employer.class + ) + public Collection getEmployers() { + return employers; + } +} + </programlisting> + + <para>至此,我们已经展示了很多跟关联有关的声明定义以及属性细节. + 下面我们将深入介绍<literal>@JoinTable</literal>注解,该注解定义了联接表的表名, + 联接列数组(注解中定义数组的格式为{ A, B, C }), + 以及inverse联接列数组. + 后者是关联表中关联到<classname>Employee</classname>主键的列(the "other side").</para> + + <para>正如前面所示,被关联端不必也不能描述物理映射: + 只需要一个简单的<literal>mappedBy</literal>参数,该参数包含了主体端的属性名,这样就绑定双方的关系.</para> + </sect5> + + <sect5> + <title>默认值</title> + + <para>和其他许多注解一样,在多对多关联中很多值是自动生成. + 当双向多对多关联中没有定义任何物理映射时,Hibernate根据以下规则生成相应的值. + 关联表名:主表表名+<keycap>_</keycap>下划线+从表表名, + 关联到主表的外键名:主表名+<keycap>_</keycap>下划线+主表中的主键列名. + 关联到从表的外键名:主表中用于关联的属性名+<keycap>_</keycap>下划线+从表的主键列名. + 以上规则对于双向一对多关联同样有效.</para> + + <programlisting> +@Entity +public class Store { + @ManyToMany(cascade = CascadeType.PERSIST) + public Set<City> getImplantedIn() { + ... + } +} + +@Entity +public class City { + ... //no bidirectional relationship +} + </programlisting> + + <para>上面这个例子中,<literal>Store_Table</literal>作为联接表. + <literal>Store_id</literal>列是联接到<literal>Store</literal>表的外键. + 而<literal>implantedIn_id</literal>列则联接到<literal>City</literal>表.</para> + + <para>当双向多对多关联中没有定义任何物理映射时, Hibernate根据以下规则生成相应的值 + 关联表名: :主表表名+<keycap>_</keycap>下划线+从表表名, + 关联到主表的外键名:从表用于关联的属性名+<keycap>_</keycap>下划线+主表中的主键列名. + 关联到从表的外键名:主表用于关联的属性名+<keycap>_</keycap>下划线+从表的主键列名. + 以上规则对于双向一对多关联同样有效.</para> + + <programlisting> +@Entity +public class Store { + @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + public Set<Customer> getCustomers() { + ... + } +} + +@Entity +public class Customer { + @ManyToMany(mappedBy="customers") + public Set<Store> getStores() { + ... + } +} + </programlisting> + + <para>在上面这个例子中,<literal>Store_Customer</literal>作为联接表. + <literal>stores_id</literal>列是联接到<literal>Store</literal>表的外键, + 而<literal>customers_id</literal>列联接到<literal>City</literal>表.</para> + + </sect5> + </sect4> + </sect3> + + + <sect3> + <title>用cascading实现传播性持久化(Transitive persistence)</title> + + <para>也许你已经注意到了<literal>cascade</literal>属性接受的值为<classname>CascadeType</classname>数组. + 在EJB3中的cascade的概念和Hibernate中的传播性持久化以及cascade操作非常类似, + 但是在语义上有细微的区别,支持的cascade类型也有点区别:</para> + + <itemizedlist> + <listitem> + CascadeType.PERSIST: 如果一个实体是受管状态, 或者当persist()函数被调用时, 触发级联创建(create)操作 + </listitem> + + <listitem> + CascadeType.MERGE: 如果一个实体是受管状态, 或者当merge()函数被调用时, 触发级联合并(merge)操作 + </listitem> + + <listitem> + CascadeType.REMOVE: 当delete()函数被调用时, 触发级联删除(remove)操作 + </listitem> + + <listitem> + CascadeType.REFRESH: 当refresh()函数被调用时, 触发级联更新(refresh)操作 + </listitem> + + <listitem> + CascadeType.ALL: 以上全部 + </listitem> + </itemizedlist> + + <para>关于cascading, create/merge的语义请参考EJB3规范的6.3章节.</para> + </sect3> + + <sect3> + <title>关联关系获取</title> + + <para>通过Hibernate你可以获得直接或者延迟获取关联实体的功能. + <literal>fetch</literal>参数可以设置为<literal>FetchType.LAZY</literal> + 或者 <literal>FetchType.EAGER</literal>. + <literal>EAGER</literal>通过<literal>outer join select</literal>直接获取关联的对象, + 而<literal>LAZY</literal>(默认值)在第一次访问关联对象的时候才会触发相应的select操作. + EJBQL提供了<literal>fetch</literal>关键字,该关键字可以在进行特殊查询的时候覆盖默认值. + 这对于提高性能来说非常有效,应该根据实际的用例来判断是否选择fetch关键字.</para> + </sect3> + </sect2> + + <sect2> + <title>映射复合主键与外键</title> + + <para>组合主键使用一个可嵌入的类作为主键表示,因此你需要使用<literal>@Id</literal> + 和<literal>@Embeddable</literal>两个注解. + 还有一种方式是使用<literal>@EmbeddedId</literal>注解.注意所依赖的类必须实现 + serializable以及实现<methodname>equals()</methodname>/<methodname>hashCode()</methodname>方法. + 你也可以如<xref linkend="mapping-identifier" />一章中描述的办法使用<literal>@IdClass</literal>注解.</para> + + <programlisting> +@Entity +public class RegionalArticle implements Serializable { + + @Id + public RegionalArticlePk getPk() { ... } +} + +@Embeddable +public class RegionalArticlePk implements Serializable { ... } + </programlisting> + + <para>或者</para> + + <programlisting> +@Entity +public class RegionalArticle implements Serializable { + + @EmbeddedId + public RegionalArticlePk getPk() { ... } +} + +public class RegionalArticlePk implements Serializable { ... } + </programlisting> + + <para><literal>@Embeddable</literal> 注解默认继承了其所属实体的访问类型, + 除非显式使用了Hibernate的<literal>@AccessType</literal>注解(这个注解不是EJB3标准的一部分). + 而<literal>@JoinColumns</literal>,即<literal>@JoinColumn</literal>数组, + 定义了关联的组合外键(如果不使用缺省值的话). + 显式指明<literal>referencedColumnNames</literal>是一个好的实践方式, + 否则,Hibernate认为你使用的列顺序和主键声明的顺序一致.</para> + + <programlisting> +@Entity +public class Parent implements Serializable { + @Id + public ParentPk id; + public int age; + + @OneToMany(cascade=CascadeType.ALL) + @JoinColumns ({ + @JoinColumn(name="parentCivility", referencedColumnName = "isMale"), + @JoinColumn(name="parentLastName", referencedColumnName = "lastName"), + @JoinColumn(name="parentFirstName", referencedColumnName = "firstName") + }) + public Set<Child> children; //unidirectional + ... +} + </programlisting> + + <programlisting> +@Entity +public class Child implements Serializable { + @Id @GeneratedValue + public Integer id; + + @ManyToOne + @JoinColumns ({ + @JoinColumn(name="parentCivility", referencedColumnName = "isMale"), + @JoinColumn(name="parentLastName", referencedColumnName = "lastName"), + @JoinColumn(name="parentFirstName", referencedColumnName = "firstName") + }) + public Parent parent; //unidirectional +} + </programlisting> + + <programlisting> +@Embeddable +public class ParentPk implements Serializable { + String first... [truncated message content] |
From: <hib...@li...> - 2006-06-22 20:07:26
|
Author: ste...@jb... Date: 2006-06-22 16:07:07 -0400 (Thu, 22 Jun 2006) New Revision: 10041 Modified: trunk/Hibernate3/test/org/hibernate/test/sql/OracleEmployment.hbm.xml Log: modified to test new check attribute (i.e. <sql-XXX check="xyz"/>) Modified: trunk/Hibernate3/test/org/hibernate/test/sql/OracleEmployment.hbm.xml =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/sql/OracleEmployment.hbm.xml 2006-06-22 19:51:43 UTC (rev 10040) +++ trunk/Hibernate3/test/org/hibernate/test/sql/OracleEmployment.hbm.xml 2006-06-22 20:07:07 UTC (rev 10041) @@ -42,7 +42,7 @@ </id> <property name="name" not-null="true"/> <loader query-ref="person"/> - <sql-insert>INSERT INTO PERSON (NAME, PERID) VALUES ( UPPER(?), ? )</sql-insert> + <sql-insert callable="true" check="none">{call createPerson(?,?)}</sql-insert> <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE PERID=?</sql-update> <sql-delete>DELETE FROM PERSON WHERE PERID=?</sql-delete> </class> @@ -191,4 +191,24 @@ </drop> </database-object> + <database-object> + <create> + CREATE OR REPLACE PROCEDURE createPerson(p_name PERSON.NAME%TYPE, p_id PERSON.PERID%TYPE) + AS + rowcount INTEGER; + BEGIN + INSERT INTO PERSON ( PERID, NAME ) VALUES ( p_id, UPPER( p_name ) ); + rowcount := SQL%ROWCOUNT; + IF rowcount = 1 THEN + NULL; + ELSE + RAISE_APPLICATION_ERROR( -20001, 'Unexpected rowcount [' || rowcount || ']' ); + END IF; + END; + </create> + <drop> + DROP PROCEDURE createPerson; + </drop> + </database-object> + </hibernate-mapping> |
From: <hib...@li...> - 2006-06-22 19:56:00
|
Author: ste...@jb... Date: 2006-06-22 15:51:43 -0400 (Thu, 22 Jun 2006) New Revision: 10040 Added: trunk/Hibernate3/src/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java trunk/Hibernate3/src/org/hibernate/jdbc/Expectation.java trunk/Hibernate3/src/org/hibernate/jdbc/Expectations.java Modified: trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd trunk/Hibernate3/src/org/hibernate/jdbc/Batcher.java trunk/Hibernate3/src/org/hibernate/jdbc/BatchingBatcher.java trunk/Hibernate3/src/org/hibernate/jdbc/NonBatchingBatcher.java trunk/Hibernate3/src/org/hibernate/mapping/Collection.java trunk/Hibernate3/src/org/hibernate/mapping/Join.java trunk/Hibernate3/src/org/hibernate/mapping/PersistentClass.java trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java trunk/Hibernate3/src/org/hibernate/persister/collection/BasicCollectionPersister.java trunk/Hibernate3/src/org/hibernate/persister/collection/OneToManyPersister.java trunk/Hibernate3/src/org/hibernate/persister/entity/AbstractEntityPersister.java trunk/Hibernate3/src/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java trunk/Hibernate3/src/org/hibernate/persister/entity/SingleTableEntityPersister.java trunk/Hibernate3/src/org/hibernate/persister/entity/UnionSubclassEntityPersister.java trunk/Hibernate3/src/org/hibernate/tool/hbm2ddl/SchemaExport.java Log: HHH-1792 - proper CallableStatement processing; HHH-1507 - mapping DTD typo; log SQLWarnings on SchemaExport Modified: trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/cfg/HbmBinder.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -22,6 +22,7 @@ import org.hibernate.engine.FilterDefinition; import org.hibernate.engine.NamedQueryDefinition; import org.hibernate.engine.Versioning; +import org.hibernate.engine.ExecuteUpdateResultCheckStyle; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.mapping.Any; import org.hibernate.mapping.Array; @@ -668,23 +669,20 @@ throws MappingException { Element element = node.element( "sql-insert" ); if ( element != null ) { - boolean callable = false; - callable = isCallable( element ); - model.setCustomSQLInsert( element.getTextTrim(), callable ); + boolean callable = isCallable( element ); + model.setCustomSQLInsert( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) ); } element = node.element( "sql-delete" ); if ( element != null ) { - boolean callable = false; - callable = isCallable( element ); - model.setCustomSQLDelete( element.getTextTrim(), callable ); + boolean callable = isCallable( element ); + model.setCustomSQLDelete( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) ); } element = node.element( "sql-update" ); if ( element != null ) { - boolean callable = false; - callable = isCallable( element ); - model.setCustomSQLUpdate( element.getTextTrim(), callable ); + boolean callable = isCallable( element ); + model.setCustomSQLUpdate( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) ); } element = node.element( "loader" ); @@ -696,53 +694,46 @@ private static void handleCustomSQL(Element node, Join model) throws MappingException { Element element = node.element( "sql-insert" ); if ( element != null ) { - boolean callable = false; - callable = isCallable( element ); - model.setCustomSQLInsert( element.getTextTrim(), callable ); + boolean callable = isCallable( element ); + model.setCustomSQLInsert( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) ); } element = node.element( "sql-delete" ); if ( element != null ) { - boolean callable = false; - callable = isCallable( element ); - model.setCustomSQLDelete( element.getTextTrim(), callable ); + boolean callable = isCallable( element ); + model.setCustomSQLDelete( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) ); } element = node.element( "sql-update" ); if ( element != null ) { - boolean callable = false; - callable = isCallable( element ); - model.setCustomSQLUpdate( element.getTextTrim(), callable ); + boolean callable = isCallable( element ); + model.setCustomSQLUpdate( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) ); } } private static void handleCustomSQL(Element node, Collection model) throws MappingException { Element element = node.element( "sql-insert" ); if ( element != null ) { - boolean callable = false; - callable = isCallable( element, true ); - model.setCustomSQLInsert( element.getTextTrim(), callable ); + boolean callable = isCallable( element, true ); + model.setCustomSQLInsert( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) ); } element = node.element( "sql-delete" ); if ( element != null ) { - boolean callable = false; - callable = isCallable( element, true ); - model.setCustomSQLDelete( element.getTextTrim(), callable ); + boolean callable = isCallable( element, true ); + model.setCustomSQLDelete( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) ); } element = node.element( "sql-update" ); if ( element != null ) { - boolean callable = false; - callable = isCallable( element, true ); - model.setCustomSQLUpdate( element.getTextTrim(), callable ); + boolean callable = isCallable( element, true ); + model.setCustomSQLUpdate( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) ); } element = node.element( "sql-delete-all" ); if ( element != null ) { - boolean callable = false; - callable = isCallable( element, true ); - model.setCustomSQLDeleteAll( element.getTextTrim(), callable ); + boolean callable = isCallable( element, true ); + model.setCustomSQLDeleteAll( element.getTextTrim(), callable, getResultCheckStyle( element, callable ) ); } } @@ -762,6 +753,16 @@ return false; } + private static ExecuteUpdateResultCheckStyle getResultCheckStyle(Element element, boolean callable) throws MappingException { + Attribute attr = element.attribute( "check" ); + if ( attr == null ) { + // use COUNT as the default. This mimics the old behavior, although + // NONE might be a better option moving forward in the case of callable + return ExecuteUpdateResultCheckStyle.COUNT; + } + return ExecuteUpdateResultCheckStyle.parse( attr.getValue() ); + } + public static void bindUnionSubclass(Element node, UnionSubclass unionSubclass, Mappings mappings, java.util.Map inheritedMetas) throws MappingException { Added: trunk/Hibernate3/src/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/engine/ExecuteUpdateResultCheckStyle.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -0,0 +1,73 @@ +package org.hibernate.engine; + +import java.io.Serializable; +import java.io.ObjectStreamException; +import java.io.InvalidObjectException; + +/** + * For persistence operations (INSERT, UPDATE, DELETE) what style of determining + * results (success/failure) is to be used. + * + * @author Steve Ebersole + */ +public class ExecuteUpdateResultCheckStyle implements Serializable { + /** + * Do not perform checking. Either user simply does not want checking, or is + * indicating a {@link java.sql.CallableStatement} execution in which the + * checks are being performed explicitly and failures are handled through + * propogation of {@link java.sql.SQLException}s. + */ + public static final ExecuteUpdateResultCheckStyle NONE = new ExecuteUpdateResultCheckStyle( "none" ); + /** + * Perform row-count checking. Row counts are the int values returned by both + * {@link java.sql.PreparedStatement#executeUpdate()} and + * {@link java.sql.Statement#executeBatch()}. These values are checked + * against some expected count. + */ + public static final ExecuteUpdateResultCheckStyle COUNT = new ExecuteUpdateResultCheckStyle( "rowcount" ); + /** + * Essentially the same as {@link #COUNT} except that the row count actually + * comes from an output parameter registered as part of a + * {@link java.sql.CallableStatement}. This style explicitly prohibits + * statement batching from being used... + */ + public static final ExecuteUpdateResultCheckStyle PARAM = new ExecuteUpdateResultCheckStyle( "param" ); + + private final String name; + + private ExecuteUpdateResultCheckStyle(String name) { + this.name = name; + } + + private Object readResolve() throws ObjectStreamException { + Object resolved = parse( name ); + if ( resolved == null ) { + throw new InvalidObjectException( "unknown result style [" + name + "]" ); + } + return resolved; + } + + public static ExecuteUpdateResultCheckStyle parse(String name) { + if ( name.equals( NONE.name ) ) { + return NONE; + } + else if ( name.equals( COUNT.name ) ) { + return COUNT; + } + else if ( name.equals( PARAM.name ) ) { + return PARAM; + } + else { + return null; + } + } + + public static ExecuteUpdateResultCheckStyle determineDefault(String customSql, boolean callable) { + if ( customSql == null ) { + return COUNT; + } + else { + return callable ? PARAM : COUNT; + } + } +} Modified: trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd =================================================================== --- trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/hibernate-mapping-3.0.dtd 2006-06-22 19:51:43 UTC (rev 10040) @@ -377,7 +377,7 @@ <!-- Declares a one-to-one association between two entities (Or from a component, component element, etc. to an entity). --> -<!ELEMENT one-to-one (meta*|formula*)> +<!ELEMENT one-to-one (meta*,formula*)> <!ATTLIST one-to-one name CDATA #REQUIRED> <!ATTLIST one-to-one formula CDATA #IMPLIED> <!ATTLIST one-to-one access CDATA #IMPLIED> @@ -990,16 +990,20 @@ <!-- custom sql operations --> <!ELEMENT sql-insert (#PCDATA)> - <!ATTLIST sql-insert callable (true|false) "false"> + <!ATTLIST sql-insert callable (true|false) "false"> + <!ATTLIST sql-insert check (none|rowcount|param) #IMPLIED> <!ELEMENT sql-update (#PCDATA)> - <!ATTLIST sql-update callable (true|false) "false"> + <!ATTLIST sql-update callable (true|false) "false"> + <!ATTLIST sql-update check (none|rowcount|param) #IMPLIED> <!ELEMENT sql-delete (#PCDATA)> - <!ATTLIST sql-delete callable (true|false) "false"> + <!ATTLIST sql-delete callable (true|false) "false"> + <!ATTLIST sql-delete check (none|rowcount|param) #IMPLIED> <!ELEMENT sql-delete-all (#PCDATA)> <!ATTLIST sql-delete-all callable (true|false) "false"> + <!ATTLIST sql-delete-all check (none|rowcount|param) #IMPLIED> <!-- Element for defining "auxiliary" database objects. Must be one of two forms: Modified: trunk/Hibernate3/src/org/hibernate/jdbc/Batcher.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/jdbc/Batcher.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/jdbc/Batcher.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -86,7 +86,7 @@ * (might be called many times before a single call to <tt>executeBatch()</tt>). * After setting parameters, call <tt>addToBatch</tt> - do not execute the * statement explicitly. - * @see Batcher#addToBatch(int) + * @see Batcher#addToBatch */ public PreparedStatement prepareBatchStatement(String sql) throws SQLException, HibernateException; @@ -95,7 +95,7 @@ * (might be called many times before a single call to <tt>executeBatch()</tt>). * After setting parameters, call <tt>addToBatch</tt> - do not execute the * statement explicitly. - * @see Batcher#addToBatch(int) + * @see Batcher#addToBatch */ public CallableStatement prepareBatchCallableStatement(String sql) throws SQLException, HibernateException; @@ -103,7 +103,7 @@ * Add an insert / delete / update to the current batch (might be called multiple times * for single <tt>prepareBatchStatement()</tt>) */ - public void addToBatch(int expectedRowCount) throws SQLException, HibernateException; + public void addToBatch(Expectation expectation) throws SQLException, HibernateException; /** * Execute the batch Modified: trunk/Hibernate3/src/org/hibernate/jdbc/BatchingBatcher.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/jdbc/BatchingBatcher.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/jdbc/BatchingBatcher.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -16,96 +16,58 @@ public class BatchingBatcher extends AbstractBatcher { private int batchSize; - private int[] expectedRowCounts; + private Expectation[] expectations; public BatchingBatcher(ConnectionManager connectionManager, Interceptor interceptor) { - super( connectionManager, interceptor ); - expectedRowCounts = new int[ getFactory().getSettings().getJdbcBatchSize() ]; + super( connectionManager, interceptor ); + expectations = new Expectation[ getFactory().getSettings().getJdbcBatchSize() ]; } - public void addToBatch(int expectedRowCount) throws SQLException, HibernateException { - - log.trace("Adding to batch"); + public void addToBatch(Expectation expectation) throws SQLException, HibernateException { + if ( !expectation.canBeBatched() ) { + throw new HibernateException( "attempting to batch an operation which cannot be batched" ); + } PreparedStatement batchUpdate = getStatement(); batchUpdate.addBatch(); - expectedRowCounts[ batchSize++ ] = expectedRowCount; - if ( batchSize==getFactory().getSettings().getJdbcBatchSize() ) { - //try { - doExecuteBatch(batchUpdate); - /*} - catch (SQLException sqle) { - closeStatement(batchUpdate); - throw sqle; - } - catch (HibernateException he) { - closeStatement(batchUpdate); - throw he; - }*/ + expectations[ batchSize++ ] = expectation; + if ( batchSize == getFactory().getSettings().getJdbcBatchSize() ) { + doExecuteBatch( batchUpdate ); } - } protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException { - - if (batchSize==0) { - log.debug("no batched statements to execute"); + if ( batchSize == 0 ) { + log.debug( "no batched statements to execute" ); } else { - - if ( log.isDebugEnabled() ) log.debug("Executing batch size: " + batchSize ); - + if ( log.isDebugEnabled() ) { + log.debug( "Executing batch size: " + batchSize ); + } + try { - checkRowCounts( ps.executeBatch() ); + checkRowCounts( ps.executeBatch(), ps ); } catch (RuntimeException re) { - log.error("Exception executing batch: ", re); + log.error( "Exception executing batch: ", re ); throw re; } finally { - batchSize=0; - //ps.clearBatch(); + batchSize = 0; } - + } } - private void checkRowCounts(int[] rowCounts) { - int rowCountLength = rowCounts.length; - if ( rowCountLength!=batchSize ) { - log.warn("JDBC driver did not return the expected number of row counts"); + private void checkRowCounts(int[] rowCounts, PreparedStatement ps) throws SQLException, HibernateException { + int numberOfRowCounts = rowCounts.length; + if ( numberOfRowCounts != batchSize ) { + log.warn( "JDBC driver did not return the expected number of row counts" ); } - for ( int i=0; i<rowCountLength; i++ ) { - checkRowCount( rowCounts[i], expectedRowCounts[i], i ); + for ( int i = 0; i < numberOfRowCounts; i++ ) { + expectations[i].verifyOutcome( rowCounts[i], ps, i ); } } - - private void checkRowCount(int rowCount, int expectedRowCount, int i) { - if ( rowCount==-2 ) { - if ( log.isDebugEnabled() ) log.debug("success of batch update unknown: " + i); - } - else if ( rowCount==-3 ) { - throw new HibernateException("Batch update failed: " + i); - } - else { - if ( expectedRowCount>=0 ) { - if ( rowCount<expectedRowCount ) { - throw new StaleStateException( - "Batch update returned unexpected row count from update: " + i + - " actual row count: " + rowCount + - " expected: " + expectedRowCount - ); - } - if ( rowCount>expectedRowCount ) { - throw new HibernateException( - "Batch update returned unexpected row count from update: " + i + - " actual row count: " + rowCount + - " expected: " + expectedRowCount - ); - } - } - } - } } Added: trunk/Hibernate3/src/org/hibernate/jdbc/Expectation.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/jdbc/Expectation.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/jdbc/Expectation.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -0,0 +1,17 @@ +package org.hibernate.jdbc; + +import org.hibernate.HibernateException; + +import java.sql.SQLException; +import java.sql.PreparedStatement; + +/** + * Defines an expected DML operation outcome. + * + * @author Steve Ebersole + */ +public interface Expectation { + public void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) throws SQLException, HibernateException; + public int prepare(PreparedStatement statement) throws SQLException, HibernateException; + public boolean canBeBatched(); +} Added: trunk/Hibernate3/src/org/hibernate/jdbc/Expectations.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/jdbc/Expectations.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/jdbc/Expectations.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -0,0 +1,176 @@ +package org.hibernate.jdbc; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.StaleStateException; +import org.hibernate.HibernateException; +import org.hibernate.engine.ExecuteUpdateResultCheckStyle; +import org.hibernate.util.JDBCExceptionReporter; +import org.hibernate.exception.GenericJDBCException; + +import java.sql.CallableStatement; +import java.sql.SQLException; +import java.sql.PreparedStatement; +import java.sql.Types; + +/** + * Holds various often used {@link Expectation} definitions. + * + * @author Steve Ebersole + */ +public class Expectations { + private static final Log log = LogFactory.getLog( Expectations.class ); + + public static final int USUAL_EXPECTED_COUNT = 1; + public static final int USUAL_PARAM_POSITION = 1; + + + // Base Expectation impls ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public static class BasicExpectation implements Expectation { + private final int expectedRowCount; + + protected BasicExpectation(int expectedRowCount) { + this.expectedRowCount = expectedRowCount; + if ( expectedRowCount < 0 ) { + throw new IllegalArgumentException( "Expected row count must be greater than zero" ); + } + } + + public final void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) { + rowCount = determineRowCount( rowCount, statement ); + if ( batchPosition < 0 ) { + checkNonBatched( rowCount ); + } + else { + checkBatched( rowCount, batchPosition ); + } + } + + private void checkBatched(int rowCount, int batchPosition) { + if ( rowCount == -2 ) { + if ( log.isDebugEnabled() ) { + log.debug( "success of batch update unknown: " + batchPosition ); + } + } + else if ( rowCount == -3 ) { + throw new HibernateException( "Batch update failed: " + batchPosition ); + } + else { + if ( expectedRowCount > rowCount ) { + throw new StaleStateException( + "Batch update returned unexpected row count from update [" + batchPosition + + "]; actual row count: " + rowCount + + "; expected: " + expectedRowCount + ); + } + if ( expectedRowCount < rowCount ) { + throw new HibernateException( + "Batch update returned unexpected row count from update [" + batchPosition + + "]; actual row count: " + rowCount + + "; expected: " + expectedRowCount + ); + } + } + } + + private void checkNonBatched(int rowCount) { + if ( expectedRowCount > rowCount ) { + throw new StaleStateException( + "Unexpected row count: " + rowCount + "; expected: " + expectedRowCount + ); + } + if ( expectedRowCount < rowCount ) { + throw new HibernateException( + "Unexpected row count: " + rowCount + "; expected: " + expectedRowCount + ); + } + } + + public int prepare(PreparedStatement statement) throws SQLException, HibernateException { + return 0; + } + + public boolean canBeBatched() { + return true; + } + + protected int determineRowCount(int reportedRowCount, PreparedStatement statement) { + return reportedRowCount; + } + } + + public static class BasicParamExpectation extends BasicExpectation { + private final int parameterPosition; + protected BasicParamExpectation(int expectedRowCount, int parameterPosition) { + super( expectedRowCount ); + this.parameterPosition = parameterPosition; + } + + public int prepare(PreparedStatement statement) throws SQLException, HibernateException { + toCallableStatement( statement ).registerOutParameter( parameterPosition, Types.NUMERIC ); + return 1; + } + + public boolean canBeBatched() { + return false; + } + + protected int determineRowCount(int reportedRowCount, PreparedStatement statement) { + try { + return toCallableStatement( statement ).getInt( parameterPosition ); + } + catch( SQLException sqle ) { + JDBCExceptionReporter.logExceptions( sqle, "could not extract row counts from CallableStatement" ); + throw new GenericJDBCException( "could not extract row counts from CallableStatement", sqle ); + } + } + + private CallableStatement toCallableStatement(PreparedStatement statement) { + if ( ! CallableStatement.class.isInstance( statement ) ) { + throw new HibernateException( "BasicParamExpectation operates exclusively on CallableStatements : " + statement.getClass() ); + } + return ( CallableStatement ) statement; + } + } + + + // Various Expectation instances ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + public static final Expectation NONE = new Expectation() { + public void verifyOutcome(int rowCount, PreparedStatement statement, int batchPosition) { + // explicitly perform no checking... + } + + public int prepare(PreparedStatement statement) { + return 0; + } + + public boolean canBeBatched() { + return true; + } + }; + + public static final Expectation BASIC = new BasicExpectation( USUAL_EXPECTED_COUNT ); + + public static final Expectation PARAM = new BasicParamExpectation( USUAL_EXPECTED_COUNT, USUAL_PARAM_POSITION ); + + + public static Expectation appropriateExpectation(ExecuteUpdateResultCheckStyle style) { + if ( style == ExecuteUpdateResultCheckStyle.NONE ) { + return NONE; + } + else if ( style == ExecuteUpdateResultCheckStyle.COUNT ) { + return BASIC; + } + else if ( style == ExecuteUpdateResultCheckStyle.PARAM ) { + return PARAM; + } + else { + throw new HibernateException( "unknown check style : " + style ); + } + } + + private Expectations() { + } +} Modified: trunk/Hibernate3/src/org/hibernate/jdbc/NonBatchingBatcher.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/jdbc/NonBatchingBatcher.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/jdbc/NonBatchingBatcher.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -6,7 +6,6 @@ import org.hibernate.HibernateException; import org.hibernate.Interceptor; -import org.hibernate.StaleStateException; /** * An implementation of the <tt>Batcher</tt> interface that does no batching @@ -19,23 +18,10 @@ super( connectionManager, interceptor ); } - public void addToBatch(int expectedRowCount) throws SQLException, HibernateException { - final int rowCount = getStatement().executeUpdate(); - //negative expected row count means we don't know how many rows to expect - if ( expectedRowCount>0 ) { - if ( expectedRowCount>rowCount ) { - throw new StaleStateException( - "Unexpected row count: " + rowCount + - " expected: " + expectedRowCount - ); - } - if ( expectedRowCount<rowCount ) { - throw new HibernateException( - "Unexpected row count: " + rowCount + - " expected: " + expectedRowCount - ); - } - } + public void addToBatch(Expectation expectation) throws SQLException, HibernateException { + PreparedStatement statement = getStatement(); + final int rowCount = statement.executeUpdate(); + expectation.verifyOutcome( rowCount, statement, 0 ); } protected void doExecuteBatch(PreparedStatement ps) throws SQLException, HibernateException { Modified: trunk/Hibernate3/src/org/hibernate/mapping/Collection.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/mapping/Collection.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/mapping/Collection.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -9,6 +9,7 @@ import org.hibernate.FetchMode; import org.hibernate.MappingException; import org.hibernate.engine.Mapping; +import org.hibernate.engine.ExecuteUpdateResultCheckStyle; import org.hibernate.type.CollectionType; import org.hibernate.type.Type; import org.hibernate.type.TypeFactory; @@ -60,13 +61,17 @@ private final java.util.Set synchronizedTables = new HashSet(); private String customSQLInsert; + private boolean customInsertCallable; + private ExecuteUpdateResultCheckStyle insertCheckStyle; private String customSQLUpdate; + private boolean customUpdateCallable; + private ExecuteUpdateResultCheckStyle updateCheckStyle; private String customSQLDelete; + private boolean customDeleteCallable; + private ExecuteUpdateResultCheckStyle deleteCheckStyle; private String customSQLDeleteAll; - private boolean customInsertCallable; - private boolean customUpdateCallable; - private boolean customDeleteCallable; private boolean customDeleteAllCallable; + private ExecuteUpdateResultCheckStyle deleteAllCheckStyle; private String loaderName; @@ -402,58 +407,80 @@ this.cacheRegionName = cacheRegionName; } - public String getCustomSQLDelete() { - return customSQLDelete; - } - public void setCustomSQLDelete(String customSQLDelete, boolean callable) { - this.customSQLDelete = customSQLDelete; - this.customDeleteCallable = callable; + + public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { + this.customSQLInsert = customSQLInsert; + this.customInsertCallable = callable; + this.insertCheckStyle = checkStyle; } - public String getCustomSQLDeleteAll() { - return customSQLDeleteAll; + public String getCustomSQLInsert() { + return customSQLInsert; } - public void setCustomSQLDeleteAll(String customSQLDeleteAll, boolean callable) { - this.customSQLDeleteAll = customSQLDeleteAll; - this.customDeleteAllCallable = callable; + public boolean isCustomInsertCallable() { + return customInsertCallable; } - public String getCustomSQLInsert() { - return customSQLInsert; + public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() { + return insertCheckStyle; } - public void setCustomSQLInsert(String customSQLInsert, boolean callable) { - this.customSQLInsert = customSQLInsert; - this.customInsertCallable = callable; + public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { + this.customSQLUpdate = customSQLUpdate; + this.customUpdateCallable = callable; + this.updateCheckStyle = checkStyle; } public String getCustomSQLUpdate() { return customSQLUpdate; } - public void setCustomSQLUpdate(String customSQLUpdate, boolean callable) { - this.customSQLUpdate = customSQLUpdate; - this.customUpdateCallable = callable; + public boolean isCustomUpdateCallable() { + return customUpdateCallable; } + public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() { + return updateCheckStyle; + } + + public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { + this.customSQLDelete = customSQLDelete; + this.customDeleteCallable = callable; + this.deleteCheckStyle = checkStyle; + } + + public String getCustomSQLDelete() { + return customSQLDelete; + } + public boolean isCustomDeleteCallable() { return customDeleteCallable; } + public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() { + return deleteCheckStyle; + } + + public void setCustomSQLDeleteAll(String customSQLDeleteAll, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { + this.customSQLDeleteAll = customSQLDeleteAll; + this.customDeleteAllCallable = callable; + this.deleteAllCheckStyle = checkStyle; + } + + public String getCustomSQLDeleteAll() { + return customSQLDeleteAll; + } + public boolean isCustomDeleteAllCallable() { return customDeleteAllCallable; } - public boolean isCustomInsertCallable() { - return customInsertCallable; + public ExecuteUpdateResultCheckStyle getCustomSQLDeleteAllCheckStyle() { + return deleteAllCheckStyle; } - public boolean isCustomUpdateCallable() { - return customUpdateCallable; - } - public void addFilter(String name, String condition) { filters.put( name, condition ); } Modified: trunk/Hibernate3/src/org/hibernate/mapping/Join.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/mapping/Join.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/mapping/Join.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -6,6 +6,7 @@ import java.util.Iterator; import org.hibernate.sql.Alias; +import org.hibernate.engine.ExecuteUpdateResultCheckStyle; /** * @author Gavin King @@ -24,11 +25,14 @@ // Custom SQL private String customSQLInsert; + private boolean customInsertCallable; + private ExecuteUpdateResultCheckStyle insertCheckStyle; private String customSQLUpdate; + private boolean customUpdateCallable; + private ExecuteUpdateResultCheckStyle updateCheckStyle; private String customSQLDelete; - private boolean customInsertCallable; - private boolean customUpdateCallable; private boolean customDeleteCallable; + private ExecuteUpdateResultCheckStyle deleteCheckStyle; public void addProperty(Property prop) { properties.add(prop); @@ -81,44 +85,60 @@ return properties.size(); } - public String getCustomSQLDelete() { - return customSQLDelete; + public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { + this.customSQLInsert = customSQLInsert; + this.customInsertCallable = callable; + this.insertCheckStyle = checkStyle; } - public void setCustomSQLDelete(String customSQLDelete, boolean callable) { - this.customSQLDelete = customSQLDelete; - this.customDeleteCallable = callable; - } - public String getCustomSQLInsert() { return customSQLInsert; } - public void setCustomSQLInsert(String customSQLInsert, boolean callable) { - this.customSQLInsert = customSQLInsert; - this.customInsertCallable = callable; + public boolean isCustomInsertCallable() { + return customInsertCallable; } - public String getCustomSQLUpdate() { - return customSQLUpdate; + public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() { + return insertCheckStyle; } - public void setCustomSQLUpdate(String customSQLUpdate, boolean callable) { + public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { this.customSQLUpdate = customSQLUpdate; this.customUpdateCallable = callable; + this.updateCheckStyle = checkStyle; } + public String getCustomSQLUpdate() { + return customSQLUpdate; + } + + public boolean isCustomUpdateCallable() { + return customUpdateCallable; + } + + public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() { + return updateCheckStyle; + } + + public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { + this.customSQLDelete = customSQLDelete; + this.customDeleteCallable = callable; + this.deleteCheckStyle = checkStyle; + } + + public String getCustomSQLDelete() { + return customSQLDelete; + } + public boolean isCustomDeleteCallable() { return customDeleteCallable; } - public boolean isCustomInsertCallable() { - return customInsertCallable; + public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() { + return deleteCheckStyle; } - public boolean isCustomUpdateCallable() { - return customUpdateCallable; - } public boolean isSequentialSelect() { return sequentialSelect; } @@ -129,7 +149,7 @@ public boolean isInverse() { return inverse; } - + public void setInverse(boolean leftJoin) { this.inverse = leftJoin; } @@ -137,7 +157,7 @@ public String toString() { return getClass().getName() + '(' + table.toString() + ')'; } - + public boolean isLazy() { Iterator iter = getPropertyIterator(); while ( iter.hasNext() ) { @@ -146,7 +166,7 @@ } return true; } - + public boolean isOptional() { return optional; } Modified: trunk/Hibernate3/src/org/hibernate/mapping/PersistentClass.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/mapping/PersistentClass.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/mapping/PersistentClass.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -13,6 +13,7 @@ import org.hibernate.EntityMode; import org.hibernate.dialect.Dialect; import org.hibernate.engine.Mapping; +import org.hibernate.engine.ExecuteUpdateResultCheckStyle; import org.hibernate.sql.Alias; import org.hibernate.util.EmptyIterator; import org.hibernate.util.JoinedIterator; @@ -61,11 +62,14 @@ // Custom SQL private String customSQLInsert; + private boolean customInsertCallable; + private ExecuteUpdateResultCheckStyle insertCheckStyle; private String customSQLUpdate; + private boolean customUpdateCallable; + private ExecuteUpdateResultCheckStyle updateCheckStyle; private String customSQLDelete; - private boolean customInsertCallable; - private boolean customUpdateCallable; private boolean customDeleteCallable; + private ExecuteUpdateResultCheckStyle deleteCheckStyle; private String temporaryIdTableName; private String temporaryIdTableDDL; @@ -490,9 +494,10 @@ return properties.iterator(); } - public void setCustomSQLInsert(String customSQLInsert, boolean callable) { + public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { this.customSQLInsert = customSQLInsert; this.customInsertCallable = callable; + this.insertCheckStyle = checkStyle; } public String getCustomSQLInsert() { @@ -503,9 +508,14 @@ return customInsertCallable; } - public void setCustomSQLUpdate(String customSQLUpdate, boolean callable) { + public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() { + return insertCheckStyle; + } + + public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { this.customSQLUpdate = customSQLUpdate; this.customUpdateCallable = callable; + this.updateCheckStyle = checkStyle; } public String getCustomSQLUpdate() { @@ -516,9 +526,14 @@ return customUpdateCallable; } - public void setCustomSQLDelete(String customSQLDelete, boolean callable) { + public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() { + return updateCheckStyle; + } + + public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { this.customSQLDelete = customSQLDelete; this.customDeleteCallable = callable; + this.deleteCheckStyle = checkStyle; } public String getCustomSQLDelete() { @@ -529,6 +544,10 @@ return customDeleteCallable; } + public ExecuteUpdateResultCheckStyle getCustomSQLDeleteCheckStyle() { + return deleteCheckStyle; + } + public void addFilter(String name, String condition) { filters.put(name, condition); } Modified: trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/persister/collection/AbstractCollectionPersister.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -2,11 +2,9 @@ package org.hibernate.persister.collection; import java.io.Serializable; -import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Types; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; @@ -20,6 +18,8 @@ import org.hibernate.MappingException; import org.hibernate.QueryException; import org.hibernate.TransientObjectException; +import org.hibernate.jdbc.Expectation; +import org.hibernate.jdbc.Expectations; import org.hibernate.cache.CacheConcurrencyStrategy; import org.hibernate.cache.CacheException; import org.hibernate.cache.entry.CacheEntryStructure; @@ -34,7 +34,7 @@ import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.engine.SessionImplementor; import org.hibernate.engine.SubselectFetch; -import org.hibernate.engine.ForeignKeys; +import org.hibernate.engine.ExecuteUpdateResultCheckStyle; import org.hibernate.exception.JDBCExceptionHelper; import org.hibernate.exception.SQLExceptionConverter; import org.hibernate.id.IdentifierGenerator; @@ -181,6 +181,10 @@ private final boolean updateCallable; private final boolean deleteCallable; private final boolean deleteAllCallable; + private ExecuteUpdateResultCheckStyle insertCheckStyle; + private ExecuteUpdateResultCheckStyle updateCheckStyle; + private ExecuteUpdateResultCheckStyle deleteCheckStyle; + private ExecuteUpdateResultCheckStyle deleteAllCheckStyle; private final Serializable[] spaces; @@ -418,40 +422,56 @@ //GENERATE THE SQL: //sqlSelectString = sqlSelectString(); - if ( collection.getCustomSQLDeleteAll() == null ) { - sqlDeleteString = generateDeleteString(); - deleteAllCallable = false; - } - else { - sqlDeleteString = collection.getCustomSQLDeleteAll(); - deleteAllCallable = collection.isCustomDeleteAllCallable(); - } //sqlSelectRowString = sqlSelectRowString(); + if ( collection.getCustomSQLInsert() == null ) { sqlInsertRowString = generateInsertRowString(); insertCallable = false; + insertCheckStyle = ExecuteUpdateResultCheckStyle.COUNT; } else { sqlInsertRowString = collection.getCustomSQLInsert(); insertCallable = collection.isCustomInsertCallable(); + insertCheckStyle = collection.getCustomSQLInsertCheckStyle() == null + ? ExecuteUpdateResultCheckStyle.determineDefault( collection.getCustomSQLInsert(), insertCallable ) + : collection.getCustomSQLInsertCheckStyle(); } if ( collection.getCustomSQLUpdate() == null ) { sqlUpdateRowString = generateUpdateRowString(); updateCallable = false; + updateCheckStyle = ExecuteUpdateResultCheckStyle.COUNT; } else { sqlUpdateRowString = collection.getCustomSQLUpdate(); updateCallable = collection.isCustomUpdateCallable(); + updateCheckStyle = collection.getCustomSQLUpdateCheckStyle() == null + ? ExecuteUpdateResultCheckStyle.determineDefault( collection.getCustomSQLUpdate(), insertCallable ) + : collection.getCustomSQLUpdateCheckStyle(); } + if ( collection.getCustomSQLDelete() == null ) { sqlDeleteRowString = generateDeleteRowString(); deleteCallable = false; + deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE; } else { sqlDeleteRowString = collection.getCustomSQLDelete(); deleteCallable = collection.isCustomDeleteCallable(); + deleteCheckStyle = ExecuteUpdateResultCheckStyle.NONE; } + + if ( collection.getCustomSQLDeleteAll() == null ) { + sqlDeleteString = generateDeleteString(); + deleteAllCallable = false; + deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE; + } + else { + sqlDeleteString = collection.getCustomSQLDeleteAll(); + deleteAllCallable = collection.isCustomDeleteAllCallable(); + deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.NONE; + } + sqlSelectSizeString = generateSelectSizeString( collection.isIndexed() && !collection.isMap() ); sqlDetectRowByIndexString = generateDetectRowByIndexString(); sqlDetectRowByElementString = generateDetectRowByElementString(); @@ -678,8 +698,7 @@ public Object readElement(ResultSet rs, Object owner, String[] aliases, SessionImplementor session) throws HibernateException, SQLException { - Object element = getElementType().nullSafeGet( rs, aliases, session, owner ); - return element; + return getElementType().nullSafeGet( rs, aliases, session, owner ); } public Object readIndex(ResultSet rs, String[] aliases, SessionImplementor session) @@ -891,10 +910,9 @@ } protected SelectFragment generateSelectFragment(String alias, String columnSuffix) { - SelectFragment frag = new SelectFragment() + return new SelectFragment() .setSuffix( columnSuffix ) .addColumns( alias, keyColumnNames, keyColumnAliases ); - return frag; } protected void appendElementColumns(SelectFragment frag, String elemAlias) { @@ -944,7 +962,7 @@ return qualify(alias, elementColumnNames, elementFormulaTemplates); } - private static final String[] qualify(String alias, String[] columnNames, String[] formulaTemplates) { + private static String[] qualify(String alias, String[] columnNames, String[] formulaTemplates) { int span = columnNames.length; String[] result = new String[span]; for (int i=0; i<span; i++) { @@ -998,24 +1016,50 @@ try { int offset = 1; PreparedStatement st = null; - if ( isDeleteCallable() ) { - CallableStatement callstatement = session.getBatcher() - .prepareBatchCallableStatement( getSQLDeleteString() ); - callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ? - st = callstatement; + Expectation expectation = Expectations.appropriateExpectation( getDeleteAllCheckStyle() ); + boolean callable = isDeleteAllCallable(); + boolean useBatch = expectation.canBeBatched(); + String sql = getSQLDeleteString(); + if ( useBatch ) { + if ( callable ) { + st = session.getBatcher().prepareBatchCallableStatement( sql ); + } + else { + st = session.getBatcher().prepareBatchStatement( sql ); + } } else { - st = session.getBatcher().prepareBatchStatement( getSQLDeleteString() ); + if ( callable ) { + st = session.getBatcher().prepareCallableStatement( sql ); + } + else { + st = session.getBatcher().prepareStatement( sql ); + } } + try { + offset+= expectation.prepare( st ); + writeKey( st, id, offset, session ); - session.getBatcher().addToBatch( -1 ); + if ( useBatch ) { + session.getBatcher().addToBatch( expectation ); + } + else { + expectation.verifyOutcome( st.executeUpdate(), st, -1 ); + } } catch ( SQLException sqle ) { - session.getBatcher().abortBatch( sqle ); + if ( useBatch ) { + session.getBatcher().abortBatch( sqle ); + } throw sqle; } + finally { + if ( !useBatch ) { + session.getBatcher().closeStatement( st ); + } + } if ( log.isDebugEnabled() ) { log.debug( "done deleting collection" ); @@ -1051,25 +1095,41 @@ //create all the new entries Iterator entries = collection.entries(this); if ( entries.hasNext() ) { - try { - collection.preInsert( this ); - int i = 0; - int count = 0; - while ( entries.hasNext() ) { + collection.preInsert( this ); + int i = 0; + int count = 0; + while ( entries.hasNext() ) { - final Object entry = entries.next(); - if ( collection.entryExists( entry, i ) ) { - int offset = 1; - PreparedStatement st = null; - if ( isInsertCallable() ) { - CallableStatement callstatement = session.getBatcher() - .prepareBatchCallableStatement( getSQLInsertRowString() ); - callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ? - st = callstatement; + final Object entry = entries.next(); + if ( collection.entryExists( entry, i ) ) { + int offset = 1; + PreparedStatement st = null; + Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() ); + boolean callable = isInsertCallable(); + boolean useBatch = expectation.canBeBatched(); + String sql = getSQLInsertRowString(); + + if ( useBatch ) { + if ( callable ) { + st = session.getBatcher().prepareBatchCallableStatement( sql ); } else { - st = session.getBatcher().prepareBatchStatement( getSQLInsertRowString() ); + st = session.getBatcher().prepareBatchStatement( sql ); } + } + else { + if ( callable ) { + st = session.getBatcher().prepareCallableStatement( sql ); + } + else { + st = session.getBatcher().prepareStatement( sql ); + } + } + + + try { + offset+= expectation.prepare( st ); + //TODO: copy/paste from insertRows() int loc = writeKey( st, id, offset, session ); if ( hasIdentifier ) { @@ -1078,22 +1138,36 @@ if ( hasIndex /*&& !indexIsFormula*/ ) { loc = writeIndex( st, collection.getIndex(entry, i, this), loc, session ); } - //if ( !elementIsFormula ) { - loc = writeElement(st, collection.getElement(entry), loc, session ); - //} - session.getBatcher().addToBatch( 1 ); + loc = writeElement(st, collection.getElement(entry), loc, session ); + + if ( useBatch ) { + session.getBatcher().addToBatch( expectation ); + } + else { + expectation.verifyOutcome( st.executeUpdate(), st, -1 ); + } + collection.afterRowInsert( this, entry, i ); count++; } - i++; + catch ( SQLException sqle ) { + if ( useBatch ) { + session.getBatcher().abortBatch( sqle ); + } + throw sqle; + } + finally { + if ( !useBatch ) { + session.getBatcher().closeStatement( st ); + } + } + } - if ( log.isDebugEnabled() ) { - log.debug( "done inserting collection: " + count + " rows inserted" ); - } + i++; } - catch ( SQLException sqle ) { - session.getBatcher().abortBatch( sqle ); - throw sqle; + + if ( log.isDebugEnabled() ) { + log.debug( "done inserting collection: " + count + " rows inserted" ); } } @@ -1139,48 +1213,71 @@ if ( deletes.hasNext() ) { int offset = 1; int count = 0; - PreparedStatement st = null; - if ( isDeleteCallable() ) { - CallableStatement callstatement = session.getBatcher() - .prepareBatchCallableStatement( getSQLDeleteRowString() ); - callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ? - st = callstatement; - } - else { - st = session.getBatcher().prepareBatchStatement( getSQLDeleteRowString() ); - } + while ( deletes.hasNext() ) { + PreparedStatement st = null; + Expectation expectation = Expectations.appropriateExpectation( getDeleteCheckStyle() ); + boolean callable = isDeleteCallable(); + boolean useBatch = expectation.canBeBatched(); + String sql = getSQLDeleteRowString(); - try { - int i=0; - while ( deletes.hasNext() ) { + if ( useBatch ) { + if ( callable ) { + st = session.getBatcher().prepareBatchCallableStatement( sql ); + } + else { + st = session.getBatcher().prepareBatchStatement( sql ); + } + } + else { + if ( callable ) { + st = session.getBatcher().prepareCallableStatement( sql ); + } + else { + st = session.getBatcher().prepareStatement( sql ); + } + } + + try { + expectation.prepare( st ); + Object entry = deletes.next(); int loc = offset; if ( hasIdentifier ) { - loc = writeIdentifier( st, entry, loc, session ); + writeIdentifier( st, entry, loc, session ); } else { - //if ( !isOneToMany() ) { - loc = writeKey( st, id, loc, session ); - //} - if (deleteByIndex) { - loc = writeIndexToWhere( st, entry, loc, session ); + loc = writeKey( st, id, loc, session ); + if ( deleteByIndex ) { + writeIndexToWhere( st, entry, loc, session ); } else { - loc = writeElementToWhere( st, entry, loc, session ); + writeElementToWhere( st, entry, loc, session ); } } - session.getBatcher().addToBatch( -1 ); + + if ( useBatch ) { + session.getBatcher().addToBatch( expectation ); + } + else { + expectation.verifyOutcome( st.executeUpdate(), st, -1 ); + } count++; - i++; } - } - catch ( SQLException sqle ) { - session.getBatcher().abortBatch( sqle ); - throw sqle; - } + catch ( SQLException sqle ) { + if ( useBatch ) { + session.getBatcher().abortBatch( sqle ); + } + throw sqle; + } + finally { + if ( !useBatch ) { + session.getBatcher().closeStatement( st ); + } + } - if ( log.isDebugEnabled() ) { - log.debug( "done deleting collection rows: " + count + " deleted" ); + if ( log.isDebugEnabled() ) { + log.debug( "done deleting collection rows: " + count + " deleted" ); + } } } else { @@ -1219,52 +1316,76 @@ try { //insert all the new entries - Iterator entries = collection.entries(this); + collection.preInsert( this ); + Iterator entries = collection.entries( this ); + Expectation expectation = Expectations.appropriateExpectation( getInsertCheckStyle() ); boolean callable = isInsertCallable(); - try { - collection.preInsert( this ); - int i = 0; - int count = 0; + boolean useBatch = expectation.canBeBatched(); + String sql = getSQLInsertRowString(); + int i = 0; + int count = 0; + while ( entries.hasNext() ) { int offset = 1; - while ( entries.hasNext() ) { - Object entry = entries.next(); - PreparedStatement st = null; - if ( collection.needsInserting( entry, i, elementType ) ) { + Object entry = entries.next(); + PreparedStatement st = null; + if ( collection.needsInserting( entry, i, elementType ) ) { + + if ( useBatch ) { if ( st == null ) { if ( callable ) { - CallableStatement callstatement = session.getBatcher() - .prepareBatchCallableStatement( getSQLInsertRowString() ); - callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ? - st = callstatement; + st = session.getBatcher().prepareBatchCallableStatement( sql ); } else { - st = session.getBatcher().prepareBatchStatement( getSQLInsertRowString() ); + st = session.getBatcher().prepareBatchStatement( sql ); } } + } + else { + if ( callable ) { + st = session.getBatcher().prepareCallableStatement( sql ); + } + else { + st = session.getBatcher().prepareStatement( sql ); + } + } + + try { + offset += expectation.prepare( st ); //TODO: copy/paste from recreate() - int loc = writeKey( st, id, offset, session ); + offset = writeKey( st, id, offset, session ); if ( hasIdentifier ) { - loc = writeIdentifier( st, collection.getIdentifier(entry, i), loc, session ); + offset = writeIdentifier( st, collection.getIdentifier(entry, i), offset, session ); } if ( hasIndex /*&& !indexIsFormula*/ ) { - loc = writeIndex( st, collection.getIndex(entry, i, this), loc, session ); + offset = writeIndex( st, collection.getIndex(entry, i, this), offset, session ); } - //if ( !elementIsFormula ) { - loc = writeElement(st, collection.getElement(entry), loc, session ); - //} - session.getBatcher().addToBatch( 1 ); + writeElement(st, collection.getElement(entry), offset, session ); + + if ( useBatch ) { + session.getBatcher().addToBatch( expectation ); + } + else { + expectation.verifyOutcome( st.executeUpdate(), st, -1 ); + } collection.afterRowInsert( this, entry, i ); count++; } - i++; + catch ( SQLException sqle ) { + if ( useBatch ) { + session.getBatcher().abortBatch( sqle ); + } + throw sqle; + } + finally { + if ( !useBatch ) { + session.getBatcher().closeStatement( st ); + } + } } - if ( log.isDebugEnabled() ) { - log.debug( "done inserting rows: " + count + " inserted" ); - } + i++; } - catch ( SQLException sqle ) { - session.getBatcher().abortBatch( sqle ); - throw sqle; + if ( log.isDebugEnabled() ) { + log.debug( "done inserting rows: " + count + " inserted" ); } } catch ( SQLException sqle ) { @@ -1432,18 +1553,34 @@ return insertCallable; } + protected ExecuteUpdateResultCheckStyle getInsertCheckStyle() { + return insertCheckStyle; + } + protected boolean isUpdateCallable() { return updateCallable; } + protected ExecuteUpdateResultCheckStyle getUpdateCheckStyle() { + return updateCheckStyle; + } + protected boolean isDeleteCallable() { return deleteCallable; } + protected ExecuteUpdateResultCheckStyle getDeleteCheckStyle() { + return deleteCheckStyle; + } + protected boolean isDeleteAllCallable() { return deleteAllCallable; } + protected ExecuteUpdateResultCheckStyle getDeleteAllCheckStyle() { + return deleteAllCheckStyle; + } + public String toString() { return StringHelper.unqualify( getClass().getName() ) + '(' + role + ')'; } Modified: trunk/Hibernate3/src/org/hibernate/persister/collection/BasicCollectionPersister.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/persister/collection/BasicCollectionPersister.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/persister/collection/BasicCollectionPersister.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -2,14 +2,14 @@ package org.hibernate.persister.collection; import java.io.Serializable; -import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.SQLException; -import java.sql.Types; import java.util.Iterator; import org.hibernate.HibernateException; import org.hibernate.MappingException; +import org.hibernate.jdbc.Expectations; +import org.hibernate.jdbc.Expectation; import org.hibernate.type.AssociationType; import org.hibernate.persister.entity.Joinable; import org.hibernate.cache.CacheConcurrencyStrategy; @@ -172,51 +172,76 @@ try { PreparedStatement st = null; + Expectation expectation = Expectations.appropriateExpectation( getUpdateCheckStyle() ); boolean callable = isUpdateCallable(); - Iterator entries = collection.entries(this); - try { - int i = 0; - int count = 0; - while ( entries.hasNext() ) { + boolean useBatch = expectation.canBeBatched(); + Iterator entries = collection.entries( this ); + String sql = getSQLUpdateRowString(); + int i = 0; + int count = 0; + while ( entries.hasNext() ) { + Object entry = entries.next(); + if ( collection.needsUpdating( entry, i, elementType ) ) { int offset = 1; - Object entry = entries.next(); - if ( collection.needsUpdating( entry, i, elementType ) ) { + + if ( useBatch ) { if ( st == null ) { if ( callable ) { - CallableStatement callstatement = session.getBatcher() - .prepareBatchCallableStatement( getSQLUpdateRowString() ); - callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ? (we cant make it return this without changing collectionpersister interface) - st = callstatement; + st = session.getBatcher().prepareBatchCallableStatement( sql ); } else { - st = session.getBatcher().prepareBatchStatement( getSQLUpdateRowString() ); + st = session.getBatcher().prepareBatchStatement( sql ); } } - - int loc = writeElement(st, collection.getElement(entry), offset, session ); + } + else { + if ( callable ) { + st = session.getBatcher().prepareCallableStatement( sql ); + } + else { + st = session.getBatcher().prepareStatement( sql ); + } + } + + try { + offset+= expectation.prepare( st ); + int loc = writeElement( st, collection.getElement( entry ), offset, session ); if ( hasIdentifier ) { - loc = writeIdentifier(st, collection.getIdentifier(entry, i), loc, session); + writeIdentifier( st, collection.getIdentifier( entry, i ), loc, session ); } else { loc = writeKey( st, id, loc, session ); if ( hasIndex && !indexContainsFormula ) { - loc = writeIndexToWhere( st, collection.getIndex(entry, i, this), loc, session ); + writeIndexToWhere( st, collection.getIndex( entry, i, this ), loc, session ); } else { - loc = writeElementToWhere( st, collection.getSnapshotElement(entry, i), loc, session ); + writeElementToWhere( st, collection.getSnapshotElement( entry, i ), loc, session ); } } - session.getBatcher().addToBatch( 1 ); - count++; + + if ( useBatch ) { + session.getBatcher().addToBatch( expectation ); + } + else { + expectation.verifyOutcome( st.executeUpdate(), st, -1 ); + } } - i++; + catch ( SQLException sqle ) { + if ( useBatch ) { + session.getBatcher().abortBatch( sqle ); + } + throw sqle; + } + finally { + if ( !useBatch ) { + session.getBatcher().closeStatement( st ); + } + } + count++; } - return count; + i++; } - catch ( SQLException sqle ) { - session.getBatcher().abortBatch( sqle ); - throw sqle; - } + return count; } catch ( SQLException sqle ) { throw JDBCExceptionHelper.convert( Modified: trunk/Hibernate3/src/org/hibernate/persister/collection/OneToManyPersister.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/persister/collection/OneToManyPersister.java 2006-06-21 22:29:24 UTC (rev 10039) +++ trunk/Hibernate3/src/org/hibernate/persister/collection/OneToManyPersister.java 2006-06-22 19:51:43 UTC (rev 10040) @@ -2,14 +2,14 @@ package org.hibernate.persister.collection; import java.io.Serializable; -import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.SQLException; -import java.sql.Types; import java.util.Iterator; import org.hibernate.HibernateException; import org.hibern... [truncated message content] |
From: Learn 'N E. <ho...@gr...> - 2006-06-22 13:09:12
|
Hello Friend, Build Your OWN Six Fig-ure In-co-me! This Is not the same old pro-grams You have seen before.... ==>>> www.chieleo.com This pro-gram could create high level of weal-th for many people. You probably knew that someone, somewhere would eventually come along with an idea and build something never seen before. It looks good and cool program! It pays 100% on payplan, just visit the site and see your potential income. We could have a great income while having fun at the same time. Here is our cool site: =>>> www.chieleo.com <<<= Have a Great Day! Best Regard, -Netprofit Team www.chieleo.com ***~***~***~***~***~***~***~***~***~***~***~***~*** P.S. If the site didn't work please let me know. Thank You! |
From: <hib...@li...> - 2006-06-21 22:46:34
|
Author: max...@jb... Date: 2006-06-21 18:29:24 -0400 (Wed, 21 Jun 2006) New Revision: 10039 Modified: trunk/HibernateExt/tools/build.xml trunk/HibernateExt/tools/doc/reference/en/master.xml Log: bump vno Modified: trunk/HibernateExt/tools/build.xml =================================================================== --- trunk/HibernateExt/tools/build.xml 2006-06-21 21:57:55 UTC (rev 10038) +++ trunk/HibernateExt/tools/build.xml 2006-06-21 22:29:24 UTC (rev 10039) @@ -7,7 +7,7 @@ <!-- Name of project and version, used to create filenames --> <property name="Name" value="Hibernate Tools"/> <property name="name" value="hibernate-tools"/> - <property name="version" value="3.1.0beta5"/> + <property name="version" value="3.2.0beta6"/> <property name="javadoc.packagenames" value="org.hibernate.tool"/> Modified: trunk/HibernateExt/tools/doc/reference/en/master.xml =================================================================== --- trunk/HibernateExt/tools/doc/reference/en/master.xml 2006-06-21 21:57:55 UTC (rev 10038) +++ trunk/HibernateExt/tools/doc/reference/en/master.xml 2006-06-21 22:29:24 UTC (rev 10039) @@ -14,7 +14,7 @@ <subtitle>Reference Guide</subtitle> - <releaseinfo>3.1.0.beta5</releaseinfo> + <releaseinfo>3.2.0.beta6</releaseinfo> <mediaobject> <imageobject> |
From: <hib...@li...> - 2006-06-21 21:57:57
|
Author: epbernard Date: 2006-06-21 17:57:55 -0400 (Wed, 21 Jun 2006) New Revision: 10038 Added: trunk/Hibernate3/test/org/hibernate/test/sql/SpaceShip.java Modified: trunk/Hibernate3/test/org/hibernate/test/sql/Dimension.java trunk/Hibernate3/test/org/hibernate/test/sql/General.hbm.xml trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java Log: add failing test for autodiscovery Modified: trunk/Hibernate3/test/org/hibernate/test/sql/Dimension.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/sql/Dimension.java 2006-06-21 21:11:30 UTC (rev 10037) +++ trunk/Hibernate3/test/org/hibernate/test/sql/Dimension.java 2006-06-21 21:57:55 UTC (rev 10038) @@ -10,6 +10,8 @@ private int length; private int width; + public Dimension() {} + public Dimension(int length, int width) { this.length = length; this.width = width; Modified: trunk/Hibernate3/test/org/hibernate/test/sql/General.hbm.xml =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/sql/General.hbm.xml 2006-06-21 21:11:30 UTC (rev 10037) +++ trunk/Hibernate3/test/org/hibernate/test/sql/General.hbm.xml 2006-06-21 21:57:55 UTC (rev 10038) @@ -86,6 +86,19 @@ <property name="width" column="d_width"/> </class> + <class name="SpaceShip"> + <id name="id" type="integer"> + <generator class="increment"/> + </id> + <property name="name" column="fld_name"/> + <property name="model" column="fld_model"/> + <property name="speed" column="fld_speed"/> + <component name="dimensions"> + <property name="length" column="fld_length"/> + <property name="width" column="fld_width"/> + </component> + </class> + <resultset name="org-emp-regionCode"> <return-scalar column="regionCode" type="string"/> <return alias="org" class="Organization"/> @@ -104,7 +117,32 @@ <return-join alias="emp" property="org.employments"/> </resultset> - <sql-query name="orgNamesOnly"> + <resultset name="spaceship-vol"> + <return alias="sps" class="SpaceShip"> + <return-property name="id" column="id"/> + <return-property name="name" column="name"/> + <return-property name="model" column="model"/> + <return-property name="speed" column="speed"/> + <return-property name="dimensions.length" column="length"/> + <return-property name="dimensions.width" column="width"/> + </return> + <return-scalar column="surface"/> + <return-scalar column="volume"/> + </resultset> + + <sql-query name="spaceship" resultset-ref="spaceship-vol"> + select id as id, + fld_name as name, + fld_model as model, + fld_speed as speed, + fld_length as length, + fld_width as width, + fld_length * fld_width as surface, + fld_length * fld_width *10 as volume + from SpaceShip + </sql-query> + + <sql-query name="orgNamesOnly"> <return-scalar column="NAME" type="string"/> SELECT org.NAME FROM ORGANIZATION org </sql-query> Modified: trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java 2006-06-21 21:11:30 UTC (rev 10037) +++ trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java 2006-06-21 21:57:55 UTC (rev 10038) @@ -4,6 +4,8 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.math.BigInteger; +import java.math.BigDecimal; import junit.framework.Test; import junit.framework.TestSuite; @@ -509,6 +511,35 @@ t.commit(); s.close(); + s = openSession(); + t = s.beginTransaction(); + SpaceShip enterprise = new SpaceShip(); + enterprise.setModel( "USS" ); + enterprise.setName( "Entreprise" ); + enterprise.setSpeed( 50d ); + Dimension d = new Dimension(45, 10); + enterprise.setDimensions( d ); + s.save( enterprise ); +// s.flush(); + Object[] result = (Object[]) s.getNamedQuery( "spaceship" ).uniqueResult(); + enterprise = (SpaceShip) result[0]; + assertTrue(50d == enterprise.getSpeed() ); + assertTrue( 450d == ( (BigInteger) result[1] ).doubleValue() ); + assertTrue( 4500d == ( (BigDecimal) result[2] ).doubleValue() ); + s.delete( dim ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); + s.delete(emp2); + + s.delete(jboss); + s.delete(gavin); + s.delete(ifa); + t.commit(); + s.close(); + } Added: trunk/Hibernate3/test/org/hibernate/test/sql/SpaceShip.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/sql/SpaceShip.java 2006-06-21 21:11:30 UTC (rev 10037) +++ trunk/Hibernate3/test/org/hibernate/test/sql/SpaceShip.java 2006-06-21 21:57:55 UTC (rev 10038) @@ -0,0 +1,53 @@ +//$Id: $ +package org.hibernate.test.sql; + +/** + * @author Emmanuel Bernard + */ +public class SpaceShip { + private Integer id; + private String name; + private String model; + private double speed; + private Dimension dimensions; + + public Dimension getDimensions() { + return dimensions; + } + + public void setDimensions(Dimension dimensions) { + this.dimensions = dimensions; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public double getSpeed() { + return speed; + } + + public void setSpeed(double speed) { + this.speed = speed; + } +} |
From: <hib...@li...> - 2006-06-21 21:12:18
|
Author: ste...@jb... Date: 2006-06-21 17:11:30 -0400 (Wed, 21 Jun 2006) New Revision: 10037 Added: trunk/Hibernate3/test/org/hibernate/test/sql/Dimension.java Modified: trunk/Hibernate3/test/org/hibernate/test/sql/General.hbm.xml trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java Log: mimic particular test from JPA testsuite Added: trunk/Hibernate3/test/org/hibernate/test/sql/Dimension.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/sql/Dimension.java 2006-06-21 19:42:52 UTC (rev 10036) +++ trunk/Hibernate3/test/org/hibernate/test/sql/Dimension.java 2006-06-21 21:11:30 UTC (rev 10037) @@ -0,0 +1,29 @@ +package org.hibernate.test.sql; + +/** + * Used to mimic some tests from the JPA testsuite... + * + * @author Steve Ebersole + */ +public class Dimension { + private Long id; + private int length; + private int width; + + public Dimension(int length, int width) { + this.length = length; + this.width = width; + } + + public Long getId() { + return id; + } + + public int getLength() { + return length; + } + + public int getWidth() { + return width; + } +} Modified: trunk/Hibernate3/test/org/hibernate/test/sql/General.hbm.xml =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/sql/General.hbm.xml 2006-06-21 19:42:52 UTC (rev 10036) +++ trunk/Hibernate3/test/org/hibernate/test/sql/General.hbm.xml 2006-06-21 21:11:30 UTC (rev 10037) @@ -77,7 +77,15 @@ <one-to-many class="Order"/> </set> </class> - + + <class name="Dimension"> + <id name="id" type="long"> + <generator class="increment"/> + </id> + <property name="length" column="d_len"/> + <property name="width" column="d_width"/> + </class> + <resultset name="org-emp-regionCode"> <return-scalar column="regionCode" type="string"/> <return alias="org" class="Organization"/> Modified: trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java =================================================================== --- trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java 2006-06-21 19:42:52 UTC (rev 10036) +++ trunk/Hibernate3/test/org/hibernate/test/sql/GeneralTest.java 2006-06-21 21:11:30 UTC (rev 10037) @@ -72,7 +72,7 @@ public void testFailOnNoAddEntityOrScalar() { // Note: this passes, but for the wrong reason. - // there is actually an exception thrown, but it is the database + // there is actually an exception thrown, but it is the database // throwing a sql exception because the SQL gets passed // "un-processed"... Session s = openSession(); @@ -89,7 +89,7 @@ s.close(); } } - + public void testSQLQueryInterface() { Session s = openSession(); Transaction t = s.beginTransaction(); @@ -116,13 +116,13 @@ .addJoin("pers", "emp.employee") .list(); assertEquals( l.size(), 1 ); - + t.commit(); s.close(); - + s = openSession(); t = s.beginTransaction(); - + l = s.createSQLQuery( "select {org.*}, {emp.*} " + "from ORGANIZATION org " + " left outer join EMPLOYMENT emp on org.ORGID = emp.EMPLOYER, ORGANIZATION org2" ) @@ -134,10 +134,10 @@ t.commit(); s.close(); - + s = openSession(); t = s.beginTransaction(); - + s.delete(emp); s.delete(gavin); s.delete(ifa); @@ -146,7 +146,7 @@ t.commit(); s.close(); } - + public void testResultSetMappingDefinition() { Session s = openSession(); Transaction t = s.beginTransaction(); @@ -178,7 +178,7 @@ t.commit(); s.close(); } - + public void testScalarValues() throws Exception { Session s = openSession(); Transaction t = s.beginTransaction(); @@ -254,7 +254,7 @@ t.commit(); s.close(); } - + public void testMappedAliasStrategy() { Session s = openSession(); Transaction t = s.beginTransaction(); @@ -292,8 +292,8 @@ Map m = (Map) res; assertEquals(2,m.size()); t.commit(); - s.close(); - + s.close(); + s = openSession(); t = s.beginTransaction(); sqlQuery = s.getNamedQuery("organizationreturnproperty"); @@ -308,7 +308,7 @@ assertEquals(2, m.size()); t.commit(); s.close(); - + s = openSession(); t = s.beginTransaction(); namedQuery = s.getNamedQuery("EmploymentAndPerson"); @@ -317,7 +317,7 @@ Object[] objs = (Object[]) list.get(0); assertEquals(2, objs.length); emp2 = (Employment) objs[0]; - gavin = (Person) objs[1]; + gavin = (Person) objs[1]; s.delete(emp2); s.delete(jboss); s.delete(gavin); @@ -325,7 +325,7 @@ t.commit(); s.close(); } - + /* test for native sql composite id joins which has never been implemented */ public void testCompositeIdJoinsFailureExpected() { Session s = openSession(); @@ -338,55 +338,55 @@ product.getProductId().setOrgid( "x" ); product.getProductId().setProductnumber( "1234" ); product.setName( "Hibernate 3" ); - + Order order = new Order(); order.setOrderId( new Order.OrderId() ); order.getOrderId().setOrdernumber( "1" ); order.getOrderId().setOrgid( "y" ); - + product.getOrders().add( order ); order.setProduct( product ); order.setPerson( person ); - + s.save( product ); s.save( order); s.save( person ); - + t.commit(); s.close(); - + s = openSession(); t = s.beginTransaction(); Product p = (Product) s.createQuery( "from Product p join fetch p.orders" ).list().get(0); assertTrue(Hibernate.isInitialized( p.getOrders())); t.commit(); s.close(); - + s = openSession(); t = s.beginTransaction(); - Object[] o = (Object[]) s.createSQLQuery( "select\r\n" + - " product.orgid as {product.id.orgid}," + - " product.productnumber as {product.id.productnumber}," + - " {prod_orders}.orgid as orgid3_1_,\r\n" + - " {prod_orders}.ordernumber as ordernum2_3_1_,\r\n" + + Object[] o = (Object[]) s.createSQLQuery( "select\r\n" + + " product.orgid as {product.id.orgid}," + + " product.productnumber as {product.id.productnumber}," + + " {prod_orders}.orgid as orgid3_1_,\r\n" + + " {prod_orders}.ordernumber as ordernum2_3_1_,\r\n" + " product.name as {product.name}," + - " {prod_orders.element.*}," + - /*" orders.PROD_NO as PROD4_3_1_,\r\n" + - " orders.person as person3_1_,\r\n" + - " orders.PROD_ORGID as PROD3_0__,\r\n" + - " orders.PROD_NO as PROD4_0__,\r\n" + - " orders.orgid as orgid0__,\r\n" + - " orders.ordernumber as ordernum2_0__ \r\n" +*/ - " from\r\n" + - " Product product \r\n" + - " inner join\r\n" + - " TBL_ORDER {prod_orders} \r\n" + - " on product.orgid={prod_orders}.PROD_ORGID \r\n" + + " {prod_orders.element.*}," + + /*" orders.PROD_NO as PROD4_3_1_,\r\n" + + " orders.person as person3_1_,\r\n" + + " orders.PROD_ORGID as PROD3_0__,\r\n" + + " orders.PROD_NO as PROD4_0__,\r\n" + + " orders.orgid as orgid0__,\r\n" + + " orders.ordernumber as ordernum2_0__ \r\n" +*/ + " from\r\n" + + " Product product \r\n" + + " inner join\r\n" + + " TBL_ORDER {prod_orders} \r\n" + + " on product.orgid={prod_orders}.PROD_ORGID \r\n" + " and product.productnumber={prod_orders}.PROD_NO" ) .addEntity( "product", Product.class ) .addJoin( "prod_orders", "product.orders" ) .list().get(0); - + p = (Product) o[0]; assertTrue(Hibernate.isInitialized( p.getOrders() )); assertNotNull(p.getOrders().iterator().next()); @@ -430,12 +430,12 @@ Map m = (Map) list.get(0); assertTrue(m.containsKey("Employment")); assertEquals(1,m.size()); - + list = s.createSQLQuery(getEmploymentSQL()).list(); assertEquals(1, list.size()); Object[] o = (Object[]) list.get(0); assertEquals(8, o.length); - + list = s.createSQLQuery(getEmploymentSQL()).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP).list(); assertEquals(1, list.size()); m = (Map) list.get(0); @@ -443,16 +443,16 @@ assertTrue(m.containsKey("VALUE")); assertTrue(m.containsKey("ENDDATE")); assertEquals(8, m.size()); - + list = s.createSQLQuery( getEmploymentSQLMixedScalarEntity() ).addScalar( "employerid" ).addEntity( Employment.class ).list(); assertEquals(1, list.size()); o = (Object[]) list.get(0); assertEquals(2, o.length); assertClassAssignability( o[0].getClass(), Number.class); assertClassAssignability( o[1].getClass(), Employment.class); - - - + + + Query queryWithCollection = s.getNamedQuery("organizationEmploymentsExplicitAliases"); queryWithCollection.setLong("id", jboss.getId() ); list = queryWithCollection.list(); @@ -491,6 +491,16 @@ s = openSession(); t = s.beginTransaction(); + Dimension dim = new Dimension( 3, Integer.MAX_VALUE ); + s.save( dim ); +// s.flush(); + list = s.createSQLQuery( "select d_len * d_width as surface, d_len * d_width * 10 as volume from Dimension" ).list(); + s.delete( dim ); + t.commit(); + s.close(); + + s = openSession(); + t = s.beginTransaction(); s.delete(emp2); s.delete(jboss); @@ -500,9 +510,9 @@ s.close(); } - - + + public static Test suite() { return new TestSuite(GeneralTest.class); } |