eclipselink を使用して、マルチテナント アーキテクチャを実装しようとしています。テーブル Entidade があります。Entidade の名前がテナントになります。各usuarioがEntidadeに接続されているUsuarioテーブルがあります。テーブル Usuario と Entidade にはテナントのデフォルトがあります。これは、Usuario でログインすると、Usuario がどの Entidade に属しているかを知る方法がないためです。データベースにエンティティを挿入しても、問題はありません。問題は、特に検索が子クラスの Entidade で行われる場合に、ユーザー クラスをクエリすることであり、次の例外をスローします。
[EL Warning]: metadata: 2013-09-18 11:39:50.976--ServerSession(20689274)--The tenant discriminator context property for the tenant discriminator column [USUARIO.id_tenant] on the element [class teste.Usuario] is being defaulted to: eclipselink.tenant-id.
[EL Warning]: metadata: 2013-09-18 11:39:50.993--ServerSession(20689274)--The tenant discriminator context property for the tenant discriminator column [ENTIDADE.id_tenant] on the element [class teste.Entidade] is being defaulted to: eclipselink.tenant-id.
[EL Info]: 2013-09-18 11:39:51.604--ServerSession(20689274)--EclipseLink, version: Eclipse Persistence Services - 2.5.0.v20130507-3faac2b
[EL Warning]: metadata: 2013-09-18 11:39:51.823--ServerSession(20689274)--Reverting the lazy setting on the OneToOne or ManyToOne attribute [entidade] for the entity class [class teste.Usuario] since weaving was not enabled or did not occur.
[EL Info]: connection: 2013-09-18 11:39:51.894--ServerSession(20689274)--file:/D:/java/workspaceweb/TesteTenant/bin/_teste login successful
[EL Fine]: sql: 2013-09-18 11:39:51.93--ServerSession(20689274)--Connection(29390792)--SELECT id_usuario, id_tenant, nome, id_entidade FROM USUARIO WHERE (id_tenant = ?)
bind => [usuario]
[EL Warning]: 2013-09-18 11:39:51.957--ServerSession(20689274)--Exception [EclipseLink-6174] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.QueryException
Exception Description: No value was provided for the session property [eclipselink.tenant-id]. This exception is possible when using additional criteria or tenant discriminator columns without specifying the associated contextual property. These properties must be set through Entity Manager, Entity Manager Factory or persistence unit properties. If using native EclipseLink, these properties should be set directly on the session.
Query: ReadObjectQuery(name="readEntidade" referenceClass=Entidade sql="SELECT id_entidade, id_tenant, nome FROM ENTIDADE WHERE ((id_entidade = ?) AND (id_tenant = ?))")
Exception in thread "main" javax.persistence.PersistenceException: Exception [EclipseLink-6174] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.QueryException
Exception Description: No value was provided for the session property [eclipselink.tenant-id]. This exception is possible when using additional criteria or tenant discriminator columns without specifying the associated contextual property. These properties must be set through Entity Manager, Entity Manager Factory or persistence unit properties. If using native EclipseLink, these properties should be set directly on the session.
Query: ReadObjectQuery(name="readEntidade" referenceClass=Entidade sql="SELECT id_entidade, id_tenant, nome FROM ENTIDADE WHERE ((id_entidade = ?) AND (id_tenant = ?))")
at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:479)
at teste.TesteBuscaMain.main(TesteBuscaMain.java:29)
Caused by: Exception [EclipseLink-6174] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.QueryException
Exception Description: No value was provided for the session property [eclipselink.tenant-id]. This exception is possible when using additional criteria or tenant discriminator columns without specifying the associated contextual property. These properties must be set through Entity Manager, Entity Manager Factory or persistence unit properties. If using native EclipseLink, these properties should be set directly on the session.
Query: ReadObjectQuery(name="readEntidade" referenceClass=Entidade sql="SELECT id_entidade, id_tenant, nome FROM ENTIDADE WHERE ((id_entidade = ?) AND (id_tenant = ?))")
at org.eclipse.persistence.exceptions.QueryException.missingContextPropertyForPropertyParameterExpression(QueryException.java:260)
at org.eclipse.persistence.internal.expressions.ParameterExpression.getValue(ParameterExpression.java:269)
at org.eclipse.persistence.internal.databaseaccess.DatabaseCall.translate(DatabaseCall.java:1102)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:241)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.selectOneRow(DatasourceCallQueryMechanism.java:714)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectOneRowFromTable(ExpressionQueryMechanism.java:2777)
at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectOneRow(ExpressionQueryMechanism.java:2730)
at org.eclipse.persistence.queries.ReadObjectQuery.executeObjectLevelReadQuery(ReadObjectQuery.java:526)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1155)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1114)
at org.eclipse.persistence.queries.ReadObjectQuery.execute(ReadObjectQuery.java:429)
at org.eclipse.persistence.internal.sessions.AbstractSession.internalExecuteQuery(AbstractSession.java:3207)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1797)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1779)
at org.eclipse.persistence.internal.indirection.NoIndirectionPolicy.valueFromQuery(NoIndirectionPolicy.java:326)
at org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRowInternal(ForeignReferenceMapping.java:2234)
at org.eclipse.persistence.mappings.OneToOneMapping.valueFromRowInternal(OneToOneMapping.java:1790)
at org.eclipse.persistence.mappings.ForeignReferenceMapping.valueFromRow(ForeignReferenceMapping.java:2120)
at org.eclipse.persistence.mappings.ForeignReferenceMapping.readFromRowIntoObject(ForeignReferenceMapping.java:1455)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildAttributesIntoObject(ObjectBuilder.java:455)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:862)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildWorkingCopyCloneFromRow(ObjectBuilder.java:1948)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObjectInUnitOfWork(ObjectBuilder.java:726)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:629)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:587)
at org.eclipse.persistence.internal.descriptors.ObjectBuilder.buildObject(ObjectBuilder.java:571)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.buildObject(ObjectLevelReadQuery.java:782)
at org.eclipse.persistence.queries.ReadAllQuery.registerResultInUnitOfWork(ReadAllQuery.java:848)
at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:490)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1155)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1114)
at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:402)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1202)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2894)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1797)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1779)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1744)
at org.eclipse.persistence.internal.jpa.QueryImpl.executeReadQuery(QueryImpl.java:258)
at org.eclipse.persistence.internal.jpa.QueryImpl.getResultList(QueryImpl.java:468)
... 1 more
EntityManagerFactory と EntityManager を作成するクラス:
public class JPAUtil {
private static JPAUtil instance = null;
private static EntityManagerFactory emf;
private static EntityTransaction transaction;
private static ThreadLocal entityManagers = new ThreadLocal();
static {
instance = new JPAUtil();
}
private JPAUtil() {
emf = Persistence.createEntityManagerFactory("PUAequalis");
}
public static JPAUtil getInstance() {
if (instance == null) {
instance = new JPAUtil();
}
return instance;
}
public static void openEntityManager(String tenant) {
if (entityManagers == null || entityManagers.get() == null
|| !entityManagers.get().isOpen()) {
HashMap properties = new HashMap();
EntityManager em = emf.createEntityManager();
em.setProperty("eclipselink.tenant-id", tenant);
em.setProperty(PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT, tenant);
entityManagers.set(em);
} else {
closeOpenEntityManager(tenant);
}
}
public EntityManager getEntityManager() {
return entityManagers.get();
}
public static void closeEntityManager() {
if (entityManagers != null && entityManagers.get().isOpen()) {
entityManagers.get().close();
}
}
public static void closeOpenEntityManager(String tenant) {
if (entityManagers != null && entityManagers.get().isOpen()) {
entityManagers.get().close();
entityManagers.remove();
HashMap properties = new HashMap();
properties.put("eclipselink.tenant-id", tenant);
entityManagers.set(emf.createEntityManager(properties));
}
}
public static void closeEntityManagerFactory() {
if (emf != null && emf.isOpen()) {
emf.close();
}
}
public EntityTransaction getTransaction() {
if (transaction == null || !transaction.isActive()) {
transaction = entityManagers.get().getTransaction();
}
return transaction;
}
}
persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="teste" transaction-type="RESOURCE_LOCAL">
<provider> org.eclipse.persistence.jpa.PersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/teste" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="root" />
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="eclipselink.multitenant.tenants-share-cache"
value="true" />
<!-- <property name="eclipselink.ddl-generation" value="create-tables" /> -->
<property name="eclipselink.logging.level.sql" value="ALL" />
<property name="eclipselink.logging.parameters" value="true" />
<property name="eclipselink.logging.session" value="true"/>
</properties>
</persistence-unit>
</persistence>
エンティティ:
@Entity
@Multitenant
@TenantDiscriminatorColumn(name = "id_tenant")
public class Entidade implements Serializable {
private static final long serialVersionUID = 8179478584980079687L;
@Id
@Column(name = "id_entidade", length = 10)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer idEntidade;
@Column(name = "nome")
private String nome;
@Column(name = "id_tenant", insertable=false, updatable=false)
private String idTenant;
...get and setters
}
@Entity
@Multitenant
@TenantDiscriminatorColumn(name = "id_tenant")
public class Usuario implements Serializable {
private static final long serialVersionUID = 8956344014336399968L;
@Id
@Column(name = "id_usuario", length = 10)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer idUsuario;
@Column(name = "nome")
private String nome;
@Column(name = "senha")
private String senha;
@Column(name = "nomeCompleto")
private String nomeCompleto;
@Column(name = "email")
private String email;
@Column(name = "tipo_usuario")
@Enumerated(EnumType.STRING)
private TipoUsuario tipoUsuario;
@ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL, optional = false, targetEntity = Entidade.class)
@JoinColumn(name = "id_entidade")
private Entidade entidade;
@Column(name = "id_tenant", insertable = false, updatable = false)
private String idTenant;
...get and setters
}
誰かがこの問題を抱えていますか?