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

Guy Pelletier
ORACLE Canada,
45 O'Connor Street
Suite 400
Ottawa, Ontario
Canada K1P 1A4
Oracle is committed to developing
practices and products that help protect the environment
|