EclipseLink:即使我使用@MultiTenant注释实体,如何关闭多租户

时间:2014-03-21 15:22:05

标签: java eclipselink multi-tenant

我正在使用EclipseLink进行单表多租户。

我有@ Multi-Tenant注释实体,一切正常。

是否可以在不做任何更改的情况下关闭多租户?

我知道我可以设置一个org.eclipse.persistence.annotations.Multitenant.includeCriteria()来禁用多租户。

但我的解决方案是打包并以包模式提供,并且没有任何方法可以将上面的属性设置为false。

我想要什么,即使我用@Multi-Tenant注释注释实体,甚至在数据库中有一列TENANT_ID, 但如果我没有设置PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT而不应该抛出异常,那么任何CRUD操作都应该成功。

    javax.persistence.PersistenceException: Exception [EclipseLink-6174] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): 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.

那么,是否有任何方式或任何自定义/扩展点,以便如果我设置

PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT 

那么它应该包含TENANT_ID作为标准,如果我没有设置而不是简单地不应该包含TENANT_ID作为标准?

2 个答案:

答案 0 :(得分:4)

对于eclipselink来说,这似乎是一个悬而未决的问题。我发布了一个类似的问题lately。克里斯发布了一个有用的答案,其中包含指向feature request的链接。所描述的解决方法是对具有不同多租户设置的相同表使用多个持久性单元。

我正在尝试使用alternative approach:我使用@AdditionalCriteria代替@Multitenant。通过此注释,您可以定义添加到任何数据库操作的自己的请求条件(除了本机SQL之外的少数例外)。

示例:

@AdditionalCriteria(":ADMINACCESS = 1 or this.tenant=:TENANT")

在创建实体管理器时,您可以设置参数。您可以提供关闭多租户的租户。这里的缺点是您负责租户属性。

答案 1 :(得分:0)

此问题还有另一种解决方法。 您可以使用Eclipselink MetadataSource在运行时覆盖实体类中的注释,并假装您为每个租户使用专用数据库,例如:

  MultitenantMetadata md = new MultitenantMetadata();
  md.setIncludeCriteria(false);
  md.setType(MultitenantType.TABLE_PER_TENANT.name());
  TenantTableDiscriminatorMetadata td = new TenantTableDiscriminatorMetadata();
  td.setType(TenantTableDiscriminatorType.SCHEMA.toString());
  td.setContextProperty(DISCRIMINATOR_SCHEMA_PROPERTY);
  md.setTenantTableDiscriminator(td);
  entityAccessor.setMultitenant(md);

以上将使Eclipselink从多租户角度感到高兴,但如果您的注释指定使用鉴别器列实现多租户,您的表可能仍然具有鉴别器列。

要删除discriminator列,您可以使用SessionCustomizer在创建EMF之前操作实体的EclipseLink表示,以便:

  • 删除鉴别器列
  • 更改索引和外键以删除对鉴别器列的任何引用。

通过这种方式,数据库表和DDL将不再包含鉴别器列。

        Set<String> discriminatorColumnNames = getDiscriminatorColumns(descriptor);

        for (DatabaseTable databaseTable : descriptor.getTables()) {
            List<IndexDefinition> indexDefinitions = databaseTable.getIndexes();
            for (Iterator<IndexDefinition> definitionIt = indexDefinitions.iterator(); definitionIt.hasNext();) {
                IndexDefinition indexDefinition = definitionIt.next();
                // remove qualifier from index to prevent a syntax error in DDL
                indexDefinition.setQualifier("");
                for (Iterator<String> fieldNameIt = indexDefinition.getFields().iterator(); fieldNameIt.hasNext();) {
                    if (discriminatorColumnNames.contains(fieldNameIt.next().toUpperCase())) {
                        fieldNameIt.remove();
                    }
                }
                if (indexDefinition.getFields().isEmpty()) {
                    definitionIt.remove();
                }
            }

            Map<String, List<List<String>>> uniqueConstraints = databaseTable.getUniqueConstraints();
            for (Entry<String, List<List<String>>> uc : uniqueConstraints.entrySet()) {
                List<List<String>> strings = uc.getValue();
                for (List<String> list : strings) {
                    String found = null;
                    for (String string : list) {
                        if (discriminatorColumnNames.contains(string.toUpperCase())) {
                            found = string;
                            break;
                        }
                    }
                    if (found != null) {
                        list.remove(found);
                    }
                }

            }

        }