Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] Problem with primaryKey=true in single table multitenancy discriminator

Thanks for the quick response.  I will enter a bug, possibly two :)

As for your questions, I am updating objects that were read from the db. 
The find does not use the discriminator explicitly.  In other words, I was
able to use entityManager.find( someclass.class, id ) where id did NOT include the
discriminator field.  I did see the discriminator correctly generated as part of the
find criteria in this case.  The update statement lacked the discriminator.

This system is a service layer backing a web services application.  Generally the
persistence context is recreated between the find of an object and its update as
the consumer is remote.

On Tue, Jan 29, 2013 at 3:14 PM, Guy Pelletier <guy.pelletier@xxxxxxxxxx> wrote:
Hi John,

Looks like a bug on our part with regards to the EmbeddedId setting, can you enter one and someone will have a look.


When the primary-key is set to false, unless I have missed something, you're updating something that you were able to read. Meaning you would not have been able to update it if you couldn't read it? Therefore avoiding the need of the discriminator column on the update. Or were you updating through a named query?

Cheers,
Guy

On 29/01/2013 3:53 PM, John H Goyer wrote:
Hi All,

I have run into an issue using Multitenancy and wanted to see if there was a fix available
now or in the future.  I have a workaround for now, but it ain't pretty.  I am using
2.4.0 but found the same behavior in 2.4.1.

The issue involves the primaryKey=true flag in the tenant discriminator declaration.
It affects two situations: Keys in classes that use JPA Inheritance and those that
use @EmbeddedId classes for ids.  This post concentrates on the @EmbeddedId
situation but I think the cause is the same in both cases.

I have a base class, BaseEntityFieldAccess, that is subclassed by a large number of entities.

The annotations on this class look like so:

@MappedSuperclass
@Multitenant( MultitenantType.SINGLE_TABLE )
@TenantDiscriminatorColumn( name="xxxx", contextProperty="tenant.xxxx", primaryKey=true )
public abstract class BaseEntityFieldAccess extends AbstractBaseEntity {

And its parent like this:

/**
 * Parent of all entities.  Allows convenient use of
 * <T extends AbstractBaseEntity> in generic classes.
 */
@MappedSuperclass
public abstract class AbstractBaseEntity  {
    public static final String MULTITENANT_CONTEXT_PROPERTY = "tenant.xxxx";
    public abstract <K> K getId();
   
This arrangement allows me to have an entity class that does not declare the
tenant discriminator as a field.  Example:

@Entity
@Table(name="address")
public class Address extends BaseEntityFieldAccess implements Serializable, Comparable<Address>
    @Id
    @Column(name="addressId")
    private String id;
   
The code can then do CRUD operations using this class and eclipselink magically generates
update statements that include both the id column declared in the entity (code) and the
discriminator column (xxxx) which *is* part of the primary key in the database.

PROBLEM:

When I try to use a composite primary key class in place of a single-valued @Id (with @EmbeddedId
annotation) I get an error with the primaryKey=true flag is set.  The EmbeddedId class also
does not know about the tenant discriminator.

Here's an example of the exception I am seeing:
-------------------------------------------------------------------------------
Test set: xxx.yyy.zzz.JPATestSuite
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 2.278 sec <<< FAILURE!
gov.usc.ao.TestClientDao2  Time elapsed: 0 sec  <<< ERROR!
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExcept
ionTranslationPostProcessor#0' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is o
rg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource
[applicationContext.xml]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: Exception [EclipseLi
nk-28018] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [pg1-jpa-model-test] failed.
Internal Exception: Exception [EclipseLink-7163] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions
.ValidationException
Exception Description: Entity class [class xxx.yyy.zzz.ChronosContactCode] has both an @EmbdeddedId (on attribute [id]) and
 an @Id (on attribute []. Both ID types cannot be specified on the same entity.
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java
:527)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:4
56)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
        at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:710)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:410)
        at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
        at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
        at xxx.yyy.zzz.BaseTest.initContext(BaseTest.java:88)
       
I can get around this by using @IdClass but that annotation is clumsy and confusing compared to @EmbeddedId.

Finally, note that if I take the primaryKey=true flag out of the tenant discriminator definition, the code
*appears* to work and in fact the correct SQL is generated for insert and read operations.  However, the discriminator
part of the where clause is missing for update and delete SQL.

I count myself extremely lucky to have noticed this before a production rollout!  Not good to see updates affect
entries across multiple tenants. I can provide a ton more detail of course but I wanted to find out if this issue
was on anyone's radar first.

Thanks

John Goyer
 


_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users

--

Oracle
Guy Pelletier

ORACLE Canada, 45 O'Connor Street Suite 400 Ottawa, Ontario Canada K1P 1A4

Green
            Oracle Oracle is committed to developing practices and products that help protect the environment


_______________________________________________
eclipselink-users mailing list
eclipselink-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/eclipselink-users



Back to the top