[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-4147) Eager Bidirectional association with @ManyToOne in PK lead to infinite loop

Markus Horehled (JIRA) noreply at atlassian.com
Wed Feb 10 13:17:32 EST 2010


    [ http://opensource.atlassian.com/projects/hibernate/browse/HHH-4147?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=35526#action_35526 ] 

Markus Horehled commented on HHH-4147:
--------------------------------------

Well, actually it does work fine now without any further problems

> Eager Bidirectional association with @ManyToOne in PK lead to infinite loop
> ---------------------------------------------------------------------------
>
>                 Key: HHH-4147
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-4147
>             Project: Hibernate Core
>          Issue Type: Bug
>          Components: entity-manager
>         Environment: Hibernate Annotations 3.2.0.cr2
> Hibernate EntityManager 3.2.0.cr2
> Hibernate Core 3.2.0.cr4
>            Reporter: John Schneider
>         Attachments: Test.zip
>
>
> I've tested the fix for ANN-381 and found that the improvement is not working correctly with the Entity Manager, specifically the find method.  When calling the find method on a OneToMany collection mapped by a field in a primary key class, the Entity manager goes into an infinite loop of selecting records.
> Please note that a workaround is to replace the entity managers find method with a query, such as this:
> Query query = entityManager.createQuery("select c from Card c where c.id = :id");
> query.setParameter("id", id);
> return (Card) query.getSingleResult();
> However, this workaround doesn't work if you have other entities that relate to something like the Card entity, shown below.  I'll expand on the example code from ANN-381 to show the problem of infinite looping when trying to load the related collection. 
> @Entity
> public class Card implements Serializable {
> 	@Id
> 	private String id;
> 	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "primaryKey.card")
> 	private Set<CardField> fields;
> 	public Card(String id) {
> 		this();
> 		this.id = id;
> 		
> 	}
> 	Card() {
> 		fields = new HashSet<CardField>();
> 	}
> 	public String getId() {
> 		return id;
> 	}
> 	public void setId(String id) {
> 		this.id = id;
> 	}
> 	public void addField(Card card, Key key) {
> 		fields.add(new CardField(card, key));
> 	}
> }
> @Entity
> public class CardField implements Serializable {
> 	@EmbeddedId
> 	private PrimaryKey primaryKey;
> 	CardField(Card card, Key key) {
> 		this.primaryKey = new PrimaryKey(card, key);
> 	}
> 	CardField() {
> 	}
> }
> @Embeddable
> public class PrimaryKey implements Serializable {
> 	@ManyToOne(optional = false)
> 	private Card card;
> 	@ManyToOne(optional = false)
> 	private Key key;
> 	public PrimaryKey(Card card, Key key) {
> 		this.card = card;
> 		this.key = key;
> 	}
> 	
> 	PrimaryKey() {}
> }
> @Entity
> public class Key implements Serializable {
> 	@Id
> 	private String id;
> 	public Key(String id) {
> 		this.id = id;
> 	}
> 	Key() {
> 	}
> }
> From what I can tell, this maps fine with the correct Hibernate libs and JBoss EJB Embeddable Alpha 9.  However, the Entity Manager must be creating bad query code or something with similar results to having bad queries.  I've testing with the following DAO:
> @Stateless
> public class CardDAOBean implements CardDAOLocal {
> 	@PersistenceContext
> 	private EntityManager entityManager;
> 	public void createCard(Card card) {
> 		entityManager.persist(card);
> 	}
> 	public Card findCard(String id) {
> 		return entityManager.find(Card.class, id);
> 	}
> 	public void createKey(Key key) {
> 		entityManager.persist(key);
> 	}
> }
> The Test class:
> public class EJBTest {
> 	private Card card;
> 	private Key key;
> 	public static void main(String[] args) {
> 		TestRunner.run(suite());
> 	}
> 	public static junit.framework.Test suite() {
> 		TestSuite suite = new TestSuite("Test for ANN-381");
> 		suite.addTest(new JUnit4TestAdapter(EJBTest.class));
> 		// setup test so that embedded JBoss is started/stopped once for all
> 		// tests here.
> 		TestSetup wrapper = new TestSetup(suite) {
> 			protected void setUp() {
> 				startupEmbeddedJboss();
> 			}
> 			protected void tearDown() {
> 				shutdownEmbeddedJboss();
> 			}
> 		};
> 		return wrapper;
> 	}
> 	@Before
> 	public void setup() {
> 		card = new Card("cardId");
> 		key = new Key("keyId");
> 		card.addField(card, key);
> 	}
> 	@Test
> 	public void persist() throws Exception {
> 		InitialContext ctx = getInitialContext();
> 		CardDAOLocal CardDAOLocal = (CardDAOLocal) ctx.lookup("CardDAOBean/local");
> 		CardDAOLocal.createKey(key);
> 		CardDAOLocal.createCard(card);
> 		Card card = CardDAOLocal.findCard(this.card.getId());
> 		assertNotNull(card);
> 	}
> 	private static void startupEmbeddedJboss() {
> 		EJB3StandaloneBootstrap.boot(null);
> 		EJB3StandaloneBootstrap.scanClasspath();
> 	}
> 	private static void shutdownEmbeddedJboss() {
> 		EJB3StandaloneBootstrap.shutdown();
> 	}
> 	public static InitialContext getInitialContext() throws Exception {
> 		Hashtable properties = getInitialContextProperties();
> 		return new InitialContext(properties);
> 	}
> 	private static Hashtable getInitialContextProperties() {
> 		Hashtable<String, String> props = new Hashtable<String, String>();
> 		props.put("java.naming.factory.initial",
> 				"org.jnp.interfaces.LocalOnlyContextFactory");
> 		props.put("java.naming.factory.url.pkgs",
> 				"org.jboss.naming:org.jnp.interfaces");
> 		return props;
> 	}
> }
> Here's some relevant  debugging output:
> Row insert: update CardField set card_id=? where card_id=? and key_id=?
> Row delete: update CardField set card_id=null where card_id=? and card_id=? and key_id=?
> One-shot delete: update CardField set card_id=null where card_id=?
> Static select for entity entity.CardField: select cardfield0_.card_id as card2_1_0_, cardfield0_.key_id as key1_1_0_ from CardField cardfield0_ where cardfield0_.card_id=? and cardfield0_.key_id=?
> Static select for action ACTION_MERGE on entity entity.CardField: select cardfield0_.card_id as card2_1_0_, cardfield0_.key_id as key1_1_0_ from CardField cardfield0_ where cardfield0_.card_id=? and cardfield0_.key_id=?
> Static select for action ACTION_REFRESH on entity entity.CardField: select cardfield0_.card_id as card2_1_0_, cardfield0_.key_id as key1_1_0_ from CardField cardfield0_ where cardfield0_.card_id=? and cardfield0_.key_id=?
> Static select for entity entity.Card: select card0_.id as id0_1_, fields1_.card_id as card2_3_, fields1_.key_id as key1_3_, fields1_.card_id as card2_1_0_, fields1_.key_id as key1_1_0_ from Card card0_ left outer join CardField fields1_ on card0_.id=fields1_.card_id where card0_.id=?
> Static select for entity entity.Card: select card0_.id as id0_1_, fields1_.card_id as card2_3_, fields1_.key_id as key1_3_, fields1_.card_id as card2_1_0_, fields1_.key_id as key1_1_0_ from Card card0_ left outer join CardField fields1_ on card0_.id=fields1_.card_id where card0_.id=?
> Static select for entity entity.Card: select card0_.id as id0_0_ from Card card0_ where card0_.id=?
> Static select for entity entity.Card: select card0_.id as id0_0_ from Card card0_ where card0_.id=?
> Static select for entity entity.Card: select card0_.id as id0_0_ from Card card0_ where card0_.id=?
> Static select for action ACTION_MERGE on entity entity.Card: select card0_.id as id0_1_, fields1_.card_id as card2_3_, fields1_.key_id as key1_3_, fields1_.card_id as card2_1_0_, fields1_.key_id as key1_1_0_ from Card card0_ left outer join CardField fields1_ on card0_.id=fields1_.card_id where card0_.id=?
> Static select for action ACTION_REFRESH on entity entity.Card: select card0_.id as id0_1_, fields1_.card_id as card2_3_, fields1_.key_id as key1_3_, fields1_.card_id as card2_1_0_, fields1_.key_id as key1_1_0_ from Card card0_ left outer join CardField fields1_ on card0_.id=fields1_.card_id where card0_.id=?
> Static select for entity entity.Key: select key0_.id as id2_0_ from Key key0_ where key0_.id=?
> Static select for entity entity.Key: select key0_.id as id2_0_ from Key key0_ where key0_.id=?
> Static select for entity entity.Key: select key0_.id as id2_0_ from Key key0_ where key0_.id=?
> Static select for entity entity.Key: select key0_.id as id2_0_ from Key key0_ where key0_.id=?
> Static select for entity entity.Key: select key0_.id as id2_0_ from Key key0_ where key0_.id=?
> Static select for action ACTION_MERGE on entity entity.Key: select key0_.id as id2_0_ from Key key0_ where key0_.id=?
> Static select for action ACTION_REFRESH on entity entity.Key: select key0_.id as id2_0_ from Key key0_ where key0_.id=?
> Static select for one-to-many entity.Card.fields: select fields0_.card_id as card2_1_, fields0_.key_id as key1_1_, fields0_.card_id as card2_1_0_, fields0_.key_id as key1_1_0_ from CardField fields0_ where fields0_.card_id=?
> When I call the findCard method in my EJB, the entity manager keeps looping through the select process several hundred times, and then dies from a stack overflow.
> Here's a sample of looping:
> DEBUG 17-09 21:17:18,328 (Log4JLogger.java:debug:84)  -select card0_.id as id0_1_, fields1_.card_id as card2_3_, fields1_.key_id as key1_3_, fields1_.card_id as card2_1_0_, fields1_.key_id as key1_1_0_ from Card card0_ left outer join CardField fields1_ on card0_.id=fields1_.card_id where card0_.id=?
> DEBUG 17-09 21:17:18,343 (Log4JLogger.java:debug:84)  -about to open ResultSet (open ResultSets: 0, globally: 0)
> DEBUG 17-09 21:17:18,343 (Log4JLogger.java:debug:84)  -loading entity: [entity.Card#cardId]
> DEBUG 17-09 21:17:18,359 (Log4JLogger.java:debug:84)  -about to open PreparedStatement (open PreparedStatements: 1, globally: 1)
> DEBUG 17-09 21:17:18,359 (Log4JLogger.java:debug:84)  -select card0_.id as id0_1_, fields1_.card_id as card2_3_, fields1_.key_id as key1_3_, fields1_.card_id as card2_1_0_, fields1_.key_id as key1_1_0_ from Card card0_ left outer join CardField fields1_ on card0_.id=fields1_.card_id where card0_.id=?
> DEBUG 17-09 21:17:18,359 (Log4JLogger.java:debug:84)  -about to open ResultSet (open ResultSets: 1, globally: 1)
> DEBUG 17-09 21:17:18,359 (Log4JLogger.java:debug:84)  -loading entity: [entity.Card#cardId]
> DEBUG 17-09 21:17:18,359 (Log4JLogger.java:debug:84)  -about to open PreparedStatement (open PreparedStatements: 2, globally: 2)
> DEBUG 17-09 21:17:18,359 (Log4JLogger.java:debug:84)  -select card0_.id as id0_1_, fields1_.card_id as card2_3_, fields1_.key_id as key1_3_, fields1_.card_id as card2_1_0_, fields1_.key_id as key1_1_0_ from Card card0_ left outer join CardField fields1_ on card0_.id=fields1_.card_id where card0_.id=?
> DEBUG 17-09 21:17:18,359 (Log4JLogger.java:debug:84)  -about to open ResultSet (open ResultSets: 2, globally: 2)
> DEBUG 17-09 21:17:18,359 (Log4JLogger.java:debug:84)  -loading entity: [entity.Card#cardId]
> DEBUG 17-09 21:17:18,359 (Log4JLogger.java:debug:84)  -about to open PreparedStatement (open PreparedStatements: 3, globally: 3)
> DEBUG 17-09 21:17:18,375 (Log4JLogger.java:debug:84)  -select card0_.id as id0_1_, fields1_.card_id as card2_3_, fields1_.key_id as key1_3_, fields1_.card_id as card2_1_0_, fields1_.key_id as key1_1_0_ from Card card0_ left outer join CardField fields1_ on card0_.id=fields1_.card_id where card0_.id=?
> DEBUG 17-09 21:17:18,375 (Log4JLogger.java:debug:84)  -about to open ResultSet (open ResultSets: 3, globally: 3)
> DEBUG 17-09 21:17:18,375 (Log4JLogger.java:debug:84)  -loading entity: [entity.Card#cardId]
> DEBUG 17-09 21:17:18,375 (Log4JLogger.java:debug:84)  -about to open PreparedStatement (open PreparedStatements: 4, globally: 4)
> DEBUG 17-09 21:17:18,375 (Log4JLogger.java:debug:84)  -select card0_.id as id0_1_, fields1_.card_id as card2_3_, fields1_.key_id as key1_3_, fields1_.card_id as card2_1_0_, fields1_.key_id as key1_1_0_ from Card card0_ left outer join CardField fields1_ on card0_.id=fields1_.card_id where card0_.id=?
> DEBUG 17-09 21:17:18,375 (Log4JLogger.java:debug:84)  -about to open ResultSet (open ResultSets: 4, globally: 4)
> DEBUG 17-09 21:17:18,375 (Log4JLogger.java:debug:84)  -loading entity: [entity.Card#cardId]

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        


More information about the hibernate-issues mailing list