[hibernate-issues] [Hibernate-JIRA] Commented: (HHH-2344) Persistent collection queued operation ignored with lazy inverse one-to-many collection.

Sebastian Gooren (JIRA) noreply at atlassian.com
Fri Sep 19 16:39:05 EDT 2008


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

Sebastian Gooren commented on HHH-2344:
---------------------------------------

I have the same issue on Hibernate 3.2.6GA;

What seems to be happening is this:
- I call remove() on an uninitialized collection
- persistentMap.remove() calls readElementByIndex(), which loads the collection
- persistentMap.remove() then stores the remove action in the operations queue
- the queue is never executed?

This is a normal use-case for me, and I still don't get why I should be required to call size() (or any other function which initializes the collection) to be able to delete an item from a persistent collection.

Entities:

- Product:

@Entity
@Table( name = "products" )
public class Product 
{
	@OneToMany( mappedBy = "pk.product", fetch = FetchType.LAZY, cascade = { CascadeType.ALL } )
	@MapKey( name = "pk.locale" )
	@OnDelete( action = OnDeleteAction.CASCADE )
	@Cascade( { org.hibernate.annotations.CascadeType.DELETE_ORPHAN } )
	@Fetch( FetchMode.SUBSELECT )
	private Map<Locale, ProductI18n> localizations = new HashMap<Locale, ProductI18n>();

	public Map<Locale, ProductI18n> getLocalizations()
	{
		return localizations;
	}
}

- ProductI18n:

@Entity
@Table( name = "products_i18n" )
public class ProductI18n
{
	@EmbeddedId
	private Pkey pk = new Pkey();

	private String name;
	@Lob
	private String description;

	protected ProductI18n()
	{
	}

	public ProductI18n( final Product product, final Locale locale )
	{
		this.pk.product = product;
		this.pk.locale = locale;
	}

	public String getName()
	{
		return name;
	}

	public void setName( String name )
	{
		this.name = name;
	}

	public String getDescription()
	{
		return description;
	}

	public void setDescription( String description )
	{
		this.description = description;
	}

	public Product getProduct()
	{
		return pk.product;
	}

	public Locale getLocale()
	{
		return pk.locale;
	}

	@Embeddable
	private static class Pkey implements Serializable
	{
		@Transient
		private static final long serialVersionUID = 1L;

		@ManyToOne( optional = false )
		@JoinColumn( name = "productid" )
		@NotNull
		private Product product;
		@NotNull
		private Locale locale;

		@Override
		public boolean equals( Object obj )
		{
			if (obj instanceof Pkey)
			{
				Pkey other = (Pkey) obj;
				return other.product.equals( product ) && other.locale.equals( locale );
			}

			return false;
		}

		@Override
		public int hashCode()
		{
			return super.hashCode();
		}
	}
}

Code:

class Testcase
{
	public void setup()
	{
		Session session = ...

		Product p = new Product();
		List<ProductI18n> localizations = p.getLocalizations();

		ProductI18n en_US = new ProductI18n( p, new Locale("en", "US") );
		en_US.setName( "product 1" );
		en_US.setDescription( "This is product1" );
		localizations.put( en_US.getLocale(), en_US );

		ProductI18n nl_NL = new ProductI18n( p, new Locale("nl", "NL") );
		nl_NL.setName( "product 1" );
		nl_NL.setDescription( "Dit is product 1" );
		localizations.put( nl_NL.getLocale(), nl_NL );

		session.persist( p );
		session.flush();
	}

	public void test()
	{
		Session session = ...;

		List<Product> products = session.createQuery( "from Product" ).list();
		for( Product p : products )
		{
			p.getLocalizations().remove( new Locale( "nl", "NL" ) );
			session.persist( p );
			session.flush();

			// getLocalizations().size() is still 2, both locally and in the database
		}
	}
}

> Persistent collection queued operation ignored with lazy inverse one-to-many collection.
> ----------------------------------------------------------------------------------------
>
>                 Key: HHH-2344
>                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2344
>             Project: Hibernate Core
>          Issue Type: Bug
>          Components: core
>    Affects Versions: 3.2.1
>         Environment: Hibernate 3.2.1
>            Reporter: Sebastien Robert
>
> I load an Object that contains a lazy inverse collection (one-to-many).
> Hibernate wrap my collection with a PersistentMap
> There is objects in the collection in the database but in my case the PersistentMap is not yet initialized.
> I perform a remove operation on the persistentMap with a known key of one of the objects.
> The map is not initialized (and the relation is an inverse one-to-many) so the map queue the removeOperation.
> I perform a get operation with the same key and the value is still returned.
> If we look closer at what happened in the PersistentMap, it's look like this.
> //*****
> public Object remove(Object key) {
>     if ( isPutQueueEnabled() ) {                             // This returned true, the
>                                                                                    // map is not yet                     
>                                                                                    // initialized
>      Object old = readElementByIndex( key );      // This method triggered
>                                                                                    // an initialization of the                   
>                                                                                    // map.
>                                                                                    // Queued operation are
>                                                                                    // processed in the after
>                                                                                    // init method
>      queueOperation( new Remove( key, old ) );  // The remove operation   
>                                                                                      // is queued.
>      return old;
>    }
>    ....
> //*******
> When i perform the get operation on the map the map is now initialized. The get is processed by the underlying map and the value is returned. The queued operation is completely ignored.
> Currently i fixed my code by performing a containsKey before the remove . The containsKey initialize the map and then the remove do not queue the operation. But by looking at all the PersistentCollection it seem that i may have the same problem using put and remove with other persistentCollection.

-- 
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