martes, 3 de julio de 2012

ADF 11g: No se puede encontrar o invalida su entidad propietaria

Un error clásico cuando se hace un Create de una fila para una entidad es:

Enlace de descarga del ejemplo

"oracle.jbo.InvalidOwnerException: JBO-25030: La entidad de detalle Y con la clave de fila null no se puede encontrar o invalida su entidad propietaria."
Error al realizar una operación Create en una tabla Detalle sin su Maestro

¿A que se debe este error?
Cuando se tiene un modelo de datos en el que existen entidades "Maestro - Detalle" se hace muy común este problema.
El problema reside en la creación de filas en la entidad Detalle sin que la entidad Maestra se encuentre en la misma página.
Supongamos el siguiente modelo de datos: 

Modelo de datos, Tabla Maestro-Detalle. Dado un idioma, tienes los portales asociados


Como se puede comprobar, existe una relación de Foreign Key entre PortalesWeb e Idiomas por el campo ID del idioma. Esto lo que supone es que:
  • Tabla Idioma es la maestra.
  • Tabla PortalesWeb es el detalle.
Por lo tanto, al generar los Business Components se generará una asociación entre las entidades forzando una Composite Association entre ambas. Esto quiere decir que existirá una relación fuerte entre ambas y no permitirá el uso de la tabla detalle de manera independiente.

Asociación generada automáticamente con los ADF BC

¿Cómo solventar el problema si queremos contribuir más detalles en una página aparte de la tabla maestra?
Existen varias soluciones al problema: Eliminar la fuerte asociación entre entidades o usar realmente la entidad detalle conjuntamente con su maestra. A continuación se describen las dos soluciones.
  • Eliminar la fuerte asociación entre las entidades. Es lo más fácil, rápido, pero poco ético puesto que se pierde la relación a nivel de modelo de la aplicación. Sin embargo, suele ser común el uso de esta solución puesto que en numerosas ocasiones el atributo que actúa de Foreign Key realmente es una List Of Values de la tabla maestra logrando así restringir los valores posibles para dicho atributo.
    Para conseguir eliminar la fuerte asociación abrir la assoc entre las dos entidades Maestro-Detalle y cambiar la siguiente configuración:
    • En el modo Overview del XML, navegar a Relationship -> Behaviour.
      Assoc entre Maestro-Detalle sin modificar
    • Desactivar Composite Association y así no existirá más dicho problema.
      Desactivando la fuerte asociación entre entidades.

  • Usar la vista del AppModule procedente de la View Link. Con esta solución se está generando una fila para un valor determinado de la entidad maestra. Por lo que no se esta violando la restricción.
    DataControl del AppModule, explicando cada vista con su solución.
Ejemplo descargable: ForeignAssocApp

Desarrollado en JDeveloper 11.1.1.6 apoyado en una BBDD Oracle XE 10g.

Datos: El ejemplo demuestra el problema de intentar crear una fila de una entidad detalle sin su maestra. Podéis modificar el assoc para comprobar que realmente el problema desaparece con la primera solución.
El modelo y los datos iniciales se encuentran en los script: script1.sql, insert.sql respectivamente
Existe una Offline DataBase en el proyecto Model para que podais cargar automáticamente el modelo de datos en un esquema de vuestra BBDD.

Referencias:

2 comentarios:

  1. Hola que tal,

    Oye espero me puedas ayudar, tengo exactamente este problema pero unicamente cuando ejecuto el ejemplo en una página JSF, cuando lo ejecuto en el AppModule corre bien no marca ningun error al insertar la fila de la entidad de detalle, ¿Qué crees que pueda ser?

    Gracias, saludos.

    ResponderEliminar
    Respuestas
    1. Me aparecia el mensaje teniendo el Maestro y Detalle en la misma pagina. Solucion: atributo SkipValidation="validateCurrentRows" en el PageDefinition:



      Ademas se sobre escribe el metodo setNewRowState del UVORowImpl.java:
      @Override
      public void setNewRowState(byte newRowState) {
      if (newRowState != Row.STATUS_INITIALIZED || this.getNewRowState() != Row.STATUS_NEW) {
      super.setNewRowState(newRowState);
      }
      }

      Eliminar