2010-07-09 11 views
10

Ich programmiere eine Webanwendung mit Weblogic und Oracle. Die Datenquelle wird über JNDI konfiguriert, mit einem eingeschränkten Datenbankbenutzer, der DML in Tabellen schreiben kann, aber nicht DDL. Wie Sie sich denken können, ist dieser Benutzer nicht der Besitzer dieser Tabellen, aber er hat Zugriff gewährt.JPA - EclipseLink - Wie Standardschema zu ändern

Lassen Sie uns sagen, dass er GUEST_USER ist

Die Anwendung PPV + Eclipse verwendet, und haben viele Einheiten bereits definiert. Ich möchte nicht in jeder einzelnen Entitätsklasse das Attribut schreiben, um das Schema zu ändern. Ich habe einen SessionCustomizer mit diesem Code versucht.

public class MyCustomizer implements SessionCustomizer{ 

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

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

Es scheint, dass etwas uninitiallized es gibt, ich bin eine Null-Zeiger-Ausnahme bekommen, ich bin nicht einmal sicher, ob dies der richtige Weg ist das Schema für die Verbindungen zu ändern, bevor sie verwendet werden. Irgendwelche Proben oder Ideen?

Vielen Dank im Voraus für Ihre Hilfe!

Antwort

16

Wenn alle Entitäten dasselbe Schema verwenden, können Sie eine XML-Zuordnungsdatei verwenden, um ein Standardschema zu definieren.

So etwas sollte funktionieren (Beispiel für JPA 2.0, ändern Sie das schema für 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 Das klingt gut –

+2

das ist gut, aber immer noch nicht dynamisch, was ist, wenn ich das Schema für zwei Versionen der gleichen App für zwei Diff-db-Instanzen geändert brauchen? –

+0

Wenn ich außerdem das Schema für einen bestimmten EntityManager mit einem 'SET search_path TO ... 'festlege, hat die Übergabe des Entity Managers an andere Methoden keine Auswirkungen. Ich nehme an, dass Wildfly (in meinem Fall) eine der Poolverbindungen verwendet, die zuvor mit dem öffentlichen Standardschema erstellt wurden. – Chris

3

Sie können Mach es programmatisch. Sie können den Standardschemawert für jede Sitzung konfigurieren.

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); 
     } 
    } 
} 

Stellen Sie dann die Sitzung Customizer zu Entity Manager Fabrik Eigenschaften:

PersistenceUnitProperties.SESSION_CUSTOMIZER 

z.B.

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

Gibt es eine JPA-Standardmethode? –

+0

Eine JPA-Standardmethode verwendet das Parameterschema in Annotation ['@ Table'] (http://docs.oracle.com/javaee/7/api/javax/Persistenz/Table.html) – Ati

0

Ich benutze EJB Recht vor Abfragen der Datenbank, so durch Interceptors mit ich in der Lage, indem Sie den aktuellen authentifizierten Benutzer das Schema in der EJB-Kontext zu setzen.

Wenn ich dann den Entity Manager erstelle, kann ich das richtige Schema einstellen. Auf diese Weise wird PostgreSQL das search_path ermitteln, um festzustellen, welches Schema abgefragt werden soll, indem das Schema nicht vor dem Tabellennamen angegeben wird.

<!-- 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(); 
     } 
    } 

Wenn Sie dann den Entity Manager erstellen, können Sie das gewünschte Schema festlegen.

Verwandte Themen