2010-07-09 6 views
10

Я программирую веб-приложение с помощью weblogic и oracle. источник данных настроен через JNDI с ограниченным пользователем базы данных, который может использовать DML в таблицах, но не может DDL. Как вы можете догадаться, этот пользователь не является владельцем этих таблиц, но ему предоставлен доступ.JPA - EclipseLink - Как изменить схему по умолчанию

Допустим, он GUEST_USER

Приложение использует JPA + EclipseLink, и есть много организаций, которые уже определены. Я не хочу писать в каждом классе сущности атрибут для изменения схемы. Я пробовал SessionCustomizer с этим кодом.

public class MyCustomizer implements SessionCustomizer{ 

    @Override 
    public void customize(Session session) throws Exception { 

    session.executeNonSelectingSQL("ALTER SESSION SET CURRENT_SCHEMA = OWNERS_SCHEMA"); 
    } 
} 

Кажется, что есть что-то uninitiallized, я получаю исключение нулевого указателя, я даже не уверен, если это способ изменить схему для соединений до их использования. Любые образцы или идеи?

Заранее благодарим за вашу помощь!

ответ

16

Если все объекты используют одну и ту же схему, вы можете использовать файл сопоставления xml для определения схемы по умолчанию.

Что-то, как это должно работать (например, для JPA 2.0, изменить SchemaLocation для 1,0)

orm.xml:

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd" 
    version="2.0"> 
    <persistence-unit-metadata> 
     <persistence-unit-defaults> 
      <schema>OWNERS_SCHEMA</schema> 
     </persistence-unit-defaults> 
    </persistence-unit-metadata> 
    . . . 
</entity-mappings> 

persistence.xml:

<persistence 
    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" 
    version="2.0" > 
    <persistence-unit name="foo"> 
     . . . 
     <mapping-file>orm.xml</mapping-file> 
     . . . 
    </persistence-unit> 
</persistence> 
+0

+1 Это звучит хорошо –

+2

Это хорошо, но все еще не динамично, что делать, если мне нужна схема, измененная для двух версий того же приложения, указывающих на два экземпляра diff db? –

+0

Кроме того, если я устанавливаю схему для определенного EntityManager с помощью 'SET search_path TO ...', передача диспетчера сущностей другим методам не имеет никаких эффектов. Я полагаю, что Wildfly (в моем случае) берет одно из подключений пула, ранее созданных с помощью схемы общего доступа – Chris

3

Вы можете сделайте это программно. Вы можете настроить значение схемы по умолчанию для каждого сеанса.

public class MySessionCustomizer implements SessionCustomizer { 

    private static String schemaName; 

    public static void setSchemaName(String schemaName) { 
     MySessionCustomizer.schemaName = schemaName; 
    } 

    @Override 
    public void customize(Session session) throws Exception { 
     if (StringUtils.hasText(this.schemaName)) { 
      session.getLogin().setTableQualifier(this.schemaName); 
     } 
    } 
} 

Затем установите сеанс настройщик для диспетчера объектов Свойства фабрики:

PersistenceUnitProperties.SESSION_CUSTOMIZER 

например

propertiesMap.put(PersistenceUnitProperties.SESSION_CUSTOMIZER, MySessionCustomizer.class.getName()); 
+1

Существует ли стандартный способ JPA? –

+0

Стандарт JPA использует схему параметров в аннотации ['@ Table'] (http://docs.oracle.ком/JavaEE/7/апи/javax/сохранение/Table.html) – Ati

0

Я использую EJB прямо перед запросом к базе данных, так что с помощью Interceptors я могу установить схему в контексте EJB глядя текущего аутентифицированного пользователя.

Затем, когда я создаю менеджер объектов, я могу установить правильную схему. Таким образом, не указывая схему перед именем таблицы, PostgreSQL будет смотреть на search_path, чтобы определить, какую схему запросить.

<!-- language: lang-java --> 

public class Interceptor { 

    Logger logger = Logger.getLogger(Interceptor.class); 

    /** 
    * 
    * @param ctx is always null before being passed to EJB implementation. We always query database 
    * for populating context data, making user's session accessible to all EJB implementations 
    * @return 
    * @throws Exception 
    */ 
    @SuppressWarnings({ "unchecked", "unused" }) 
    @AroundInvoke 
    public Object intercept(InvocationContext ctx) throws Exception { 
     Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 

     String ejbName = ctx.getMethod().getDeclaringClass().getSimpleName(); 
     String methodName = ctx.getMethod().getName(); 
     Boolean override_schema = false; 
     String overridden_schema = ""; 

     logger.info("Intercepting " + ejbName + "." + methodName); 

     if(auth != null) { 

      UserDetails userDetails = (UserDetails)auth.getPrincipal(); 
      String username = userDetails.getUsername(); 

      Collection<SimpleGrantedAuthority> permList = (Collection<SimpleGrantedAuthority>) auth.getAuthorities(); 
      List<String> permissions = new ArrayList<String>(); 

      for (SimpleGrantedAuthority authority : permList) { 
       permissions.add(authority.getAuthority()); 
      } 


      Query query = getMasterEntityManager() 
          .createNativeQuery(
       "SQL for retrieving the schema by the current logged in user"); 

      query.setParameter("username", username); 
      List<Object[]> result = null; //query.getResultList(); 

      if(result != null) { 
       logger.info("Interceptor: context set for " + username); 
       Object[] userObj = result.get(0); 

       getContext().getContextData().put("username", username); 
       getContext().getContextData().put("schema_name",(String)userObj[1]); 
      } 
     } 

     return ctx.proceed(); 
     } 
    } 

Затем, когда вы создаете диспетчер объектов, вы можете установить требуемую схему.

Смежные вопросы