M2 - Bases de dades / Apunts UF4 : BDOR1

De wikiserver
Dreceres ràpides: navegació, cerca

Características de las bases de datos objeto-relacionales

  • Las bases de datos objeto-relacionales son aquellas que han evolucionado desde el modelo relacional tradicional a un modelo híbrido que utiliza además la tecnología orientada a objetos.
  • Las clases, objetos, y herencia son directamente soportados en los esquemas de la base de datos y el lenguaje de consulta y manipulación de datos.
  • La base de datos de Oracle implementa el modelo orientado a objetos como una extensión del modelo relacional, siguiendo soportando la funcionalidad estándar de las bases de datos relacionales.
  • El modelo objeto-relacional ofrece las ventajas de las técnicas orientadas a objetos en cuanto a mejorar la reutilización y el uso intuitivo de los objetos, a la vez que se mantiene la alta capacidad de concurrencia y el rendimiento de las bases de datos relacionales.
  • Los tipos de objetos, así como las características orientadas a objeto, proporcionan un mecanismo para organizar los datos y acceder a ellos a alto nivel. Por debajo de la capa de objetos, los datos seguirán estando almacenados en columnas y tablas.
  • La reutilización de objetos permite desarrollar aplicaciones de bases de datos más rápidamente y de manera más eficiente. Al ofrecer la base de datos de Oracle soporte nativo para los tipos de objetos, permite a los desarrolladores de aplicaciones con lenguajes orientados a objetos, acceder directamente a las mismas estructuras de datos creadas en la base de datos.
  • Las tablas de bases de datos relacionales sólo contienen datos. En cambio, los objetos pueden incluir la posibilidad de realizar determinadas acciones sobre los datos.

Tipos de datos objeto

  • Un tipo de dato objeto es un tipo de dato compuesto definido por el usuario. Representa una estructura de datos así como funciones y procedimientos para manipular datos.
  • Las variables que formen la estructura de datos de un tipo de dato objeto reciben el nombre de atributos (que se corresponde con sus propiedades). Las funciones y procedimientos del tipo de dato objeto se denominan métodos(que se corresponde con sus acciones).
  • Aunque los atributos son públicos, es decir, visibles desde otros programas cliente, los programas deberían manipular los datos únicamente a través de los métodos (funciones y procedimientos) que se hayan declarado en el tipo objeto, en vez de asignar u obtener sus valores directamente. Esto es debido a que los métodos pueden hacer un chequeo de los datos de manera que se mantenga un estado apropiado en los mismos.
  • Durante la ejecución, la aplicación creará instancias de un tipo objeto, es decir, referencias a objetos reales con valores asignados en sus atributos.

Definición de tipos de objeto

  • La estructura de la definición o declaración de un tipo de objeto está dividida en una especificación y un cuerpo. La especificación define el interfaz de programación, donde se declaran los atributos así como las operaciones (métodos) para manipular los datos. En el cuerpo se implementa el código fuente de los métodos.
  • En la especificación de un tipo de objeto, todos los atributos se deben declarar antes que los métodos. Si la especificación de un tipo de objeto sólo declara atributos, no es necesario que declarar el cuerpo.No se pueden declarar atributos en el cuerpo.
  • Todas las declaraciones realizadas en la especificación del tipo de objeto son públicas, es decir, visibles fuera del tipo de objeto.
  • No se pueden declarar en la especificación constantes (CONSTANTS), excepciones (EXCEPTIONS), cursores (CURSORS) o tipos (TYPES).
  • Para definir un objeto en Oracle debes utilizar la sentencia CREATE TYPE que tiene el siguiente formato:
CREATE TYPE nombre_tipo AS OBJECT (
  Declaración_atributos
  Declaración_métodos);
  • Para reemplazar un objeto existente:
CREATE OR REPLACE TYPE nombre_tipo AS OBJECT
  • Eliminar el tip de objeto:
DROP TYPE nombre_tipo;

Ejemplo:

DROP TYPE Usuario;

Declaración de atributos

  • El tipo de dato que puede almacenar un determinado atributo puede ser cualquiera de los tipos de Oracle excepto los siguientes:
- LONG y LONG RAW .
- ROWID y UROWID .
- Los tipos específicos PL/SQL BINARY_INTEGER (y sus subtipos), BOOLEAN, PLS_INTEGER, RECORD, REF, CURSOR , %TYPE , y %ROWTYPE.
- Los tipos definidos dentro de un paquete PL/SQL.
  • No se pueden inicializar los atributos usando el operador de asignación, ni la cláusula DEFAULT , ni asignar la restricción NOT NULL.
  • El tipo de dato de un atributo puede ser otro tipo de objeto, por lo que la estructura de datos puede ser tan complicada como sea necesario.

Ejemplo:

CREATE OR REPLACE TYPE Usuario AS OBJECT (
   login VARCHAR2(10),
   nombre VARCHAR2(30),
   f_ingreso DATE,
   credito NUMBER
);
/
  • Se pueden modificar los atributos de un tipo de objeto utilizando la sentencia ALTER TYPE . Si se desean añadir nuevos atributos se añadirá la cláusula ADD ATTRIBUTE seguida de la lista de nuevos atributos con sus correspondientes tipos de dato. Utilizando MODIFY ATTRIBUTE se podrán modificar los atributos existentes, y para eliminar atributos se dispone de manera similar de DROP ATTRIBUTE .

Ejemplos

ALTER TYPE Usuario DROP ATTRIBUTE f_ingreso;

ALTER TYPE Usuario ADD ATTRIBUTE (apellidos VARCHAR2(40), localidad VARCHAR2(50));

ALTER TYPE Usuario
ADD ATTRIBUTE cp VARCHAR2(5),
MODIFY ATTRIBUTE nombre VARCHAR2(35);

Definición de métodos

  • Un método es un subprograma que declaras en la especificación de un tipo de objeto usando las palabras clave MEMBER o STATIC .
  • El nombre no puede ser el mismo que el de tipo de objeto ni el de ninguno de sus atributos.
  • Los métodos tienen dos partes: una especificación y un cuerpo.
  • En la especificación o declaración se debe encontrar el nombre del método, una lista opcional de parámetros, y, en el caso de las funciones, un tipo de dato de retorno.

Ejemplo:

CREATE OR REPLACE TYPE Usuario AS OBJECT (
   login VARCHAR2(10),
   nombre VARCHAR2(30),
   f_ingreso DATE,
   credito NUMBER,
   MEMBER PROCEDURE incrementoCredito(inc NUMBER)
);
/
  • En el cuerpo se debe indicar el código que se debe ejecutar para realizar una determinada tarea cuando el método es invocado.

Ejemplo:

CREATE OR REPLACE TYPE BODY Usuario AS
   MEMBER PROCEDURE incrementoCredito(inc NUMBER) IS
   BEGIN
     credito := credito + inc;
   END incrementoCredito;
END;
/
  • Por cada especificación de método que se indique en el bloque de especificación del tipo de objeto, debe existir su correspondiente cuerpo del método, o bien, el método debe declararse como NOT INSTANTIABLE , para indicar que el cuerpo del método se encontrará en un subtipo de ese tipo de objeto. Además, debes tener en cuenta que las cabeceras de los métodos deben coincidir exactamente en la especificación y en el cuerpo.
  • El tipo de dato de un parámetro no puede tener restricciones de tamaño. El tipo de datos puede ser cualquiera de los empleados por Oracle salvo los indicados anteriormente para los atributos. Las mismas restricciones se aplican para los tipos de retorno de las funciones.
  • El código fuente de los métodos no sólo puede escribirse en el lenguaje PL/SQL. También con otros lenguajes de programación como Java o C.
  • Puedes usar la sentencia ALTER TYPE para añadir, modificar o eliminar métodos de un tipo de objeto existente, de manera similar a la utilizada para modificar los atributos de un tipo de objeto.

Parámetro SELF

  • Un parámetro especial que puedes utilizar con los métodos MEMBER es el que recibe el nombre SELF.

Este parámetro hace referencia a una instancia (objeto) del mismo tipo de objeto. Aunque no lo declares explícitamente, este parámetro siempre se declara automáticamente.

  • El tipo de dato correspondiente al parámetro SELF será el mismo que el del objeto original. En las funciones MEMBER , si no declaras el parámetro SELF , su modo por defecto se toma como IN . En cambio, en los procedimientos MEMBER , si no se declara, se toma como IN OUT . Ten en cuenta que no puedes especificar el modo OUT para este parámetro SELF , y que los métodos STATIC no pueden

utilizar este parámetro especial.

  • Si se hace referencia al parámetro SELF dentro del cuerpo de un método, realmente se está haciendo referencia al objeto que ha invocado a dicho método. Por tanto, si utilizas SELF.nombre_atributo o SELF.nombre_método , estarás utilizando un atributo o un método del mismo objeto que ha llamado al método donde se encuentra utilizado el parámetro SELF.

Ejemplo:

MEMBER PROCEDURE setNombre(Nombre VARCHAR2) IS
   BEGIN
   /* El primer elemento (SELF.Nombre) hace referencia al atributo del tipo de objeto mientras que
      el segundo (Nombre) hace referencia al parámetro del método */
     SELF.Nombre := Nombre;
END setNombre;

Sobrecarga

  • Al igual que ocurre con los subprogramas empaquetados, los métodos pueden ser sobrecargados, es

decir, puedes utilizar el mismo nombre para métodos diferentes siempre que sus parámetros formales sean diferentes (en cantidad o tipo de dato).

  • Cuando se hace una llamada a un método, se comparan los parámetros actuales con los parámetros

formales de los métodos que se han declarado, y se ejecutará aquél en el que haya una coincidencia entre ambos tipos de parámetros.

  • Ten en cuenta que no es válida la sobrecarga de dos métodos cuyos parámetros formales se diferencian únicamente en su modo, así como tampoco en funciones que se diferencien únicamente en el valor de retorno.

Ejemplos:

MEMBER PROCEDURE setNombre(Nombre VARCHAR2)

MEMBER PROCEDURE setNombre(Nombre VARCHAR2, Apellidos VARCHAR2)

No es válido crear un nuevo método en el que se utilicen los mismos tipos de parámetros formales aunque se diferencien los nombres de los parámetros:

MEMBER PROCEDURE setNombre(Name VARCHAR2, Surname VARCHAR2)

Métodos Constructores

  • Cada tipo de objeto tiene un método constructor, que se trata de una función con el mismo nombre

que el tipo de objeto y que se encarga de inicializar los atributos y retornar una nueva instancia de ese tipo de objeto.

  • Oracle crea un método constructor por defecto para cada tipo de objeto declarado, cuyos parámetros formales coinciden en orden, nombres y tipos de datos con los atributos del tipo de objeto.
  • También puedes declarar tus propios métodos constructores, reescribiendo ese método declarado

por el sistema, o bien, definiendo un nuevo método con otros parámetros. Una de las ventajas de crear un nuevo método constructor personalizado es que se puede hacer una verificación de que los datos que se van a asignar a los atributos son correctos (por ejemplo, que cumplen una determinada restricción).

  • Si deseas reemplazar el método constructor por defecto, debes utilizar la sentencia CONSTRUCTOR

FUNCTION seguida del nombre del tipo de objeto en el que se encuentra (recuerda que los métodos constructores tienen el mismo nombre que el tipo de objeto). A continuación debes indicar los parámetros que sean necesarios de la manera habitual. Por último, debes indicar que el valor de retorno de la función es el propio objeto utilizando la cláusula RETURN SELF AS RESULT.

  • Puedes crear varios métodos constructores siguiendo las restricciones indicadas para la sobrecarga

de métodos.

Ejemplo:

CONSTRUCTOR FUNCTION Usuario(login VARCHAR2, credito NUMBER)
   RETURN SELF AS RESULT

CREATE OR REPLACE TYPE BODY Usuario AS
   CONSTRUCTOR FUNCTION Usuario(login VARCHAR2, credito NUMBER)
      RETURN SELF AS RESULT
   IS
      BEGIN
        IF (credito >= 0) THEN
           SELF.credito := credito;
        ELSE
           SELF.credito := 0;
        END IF;
        RETURN;
      END;
END;

Utilización de objetos

En los siguientes apartados vas a ver cómo puedes declarar variables que permitan almacenar objetos, darle unos valores iniciales a sus atributos, acceder al contenido de dichos atributos en cualquier momento, y llamar a los métodos que ofrece el tipo de objeto utilizado.

Declaración de objetos

Una vez que el tipo de objeto ha sido definido, éste puede ser utilizado para declarar variables de objetos de ese tipo en cualquier bloque PL/SQL, subprograma o paquete. Ese tipo de objeto lo puedes utilizar como tipo de dato para una variable, atributo, elemento de una tabla, parámetro formal, o resultado de una función, de igual manera que se utilizan los tipos de datos habituales como VARCHAR o NUMBER . Por ejemplo, para declarar una variable denominada u1, que va a permitir almacenar un objeto del tipo Usuario, debes hacer la siguiente declaración: u1 Usuario; En la declaración de cualquier procedimiento o función, incluidos los métodos del mismo tipo de objeto o de otro, se puede utilizar el tipo de dato objeto definido para indicar que debe pasarse como parámetro un objeto de dicho tipo en la llamada. Por ejemplo pensemos en un procedimiento al que se le debe pasar como parámentro un objeto del tipo Usuario: PROCEDURE setUsuario(u IN Usuario) La llamada a este método se realizaría utilizando como parámetro un objeto, como el que podemos tener en la variable declarada anteriormente: setUsuario(u1); De manera semejante una función puede retornar objetos: FUNCTION getUsuario(codigo INTEGER) RETURN Usuario Los objetos se crean durante la ejecución del código como instancias del tipo de objeto, y cada uno de ellos puede contener valores diferentes en sus atributos. El ámbito de los objetos sigue las mismas reglas habituales en PL/SQL, es decir, en un bloque o subprograma los objetos son creados (instanciados) cuando se entra en dicho bloque o subprograma y se destruyen automáticamente cuando se sale de ellos. En un paquete, los objetos son instanciados en el momento de hacer referencia al paquete y dejan de existir cuando se finaliza la sesión en la base de datos.

Inicialización de objetos

Para crear o instanciar un objeto de un determinado tipo de objeto, debes hacer una llamada a su método constructor. Esto lo puedes realizar empleando la instrucción NEW seguido del nombre del tipo de objeto como una llamada a una función en la que se indican como parámetros los valores que se desean asignar a los atributos inicialmente. En una asignación también puedes optar por hacer eso mismo omitiendo la palabra NEW . El orden de los parámetros debe coincidir con el orden en el que están declarados los atributos, así como los tipos de datos. El formato sería como el siguiente: variable_objeto := NEW Nombre_Tipo_Objeto (valor_atributo1, valor_atributo2, ...); Por ejemplo, en el caso del tipo de objeto Usuario: u1 := NEW Usuario('luitom64', 'LUIS ', 'TOMAS BRUÑA', '24/10/07', 100); En ese momento se inicializa el objeto. Hasta que no se inicializa el objeto llamando a su constructor, el objeto tiene el valor NULL . Es habitual inicializar los objetos en su declaración. u1 Usuario := NEW Usuario('luitom64', 'LUIS ', 'TOMAS BRUÑA', '24/10/07', 100); La llamada al método constructor se puede realizar en cualquier lugar en el que se puede hacer una llamada a una función de la forma habitual. Por ejemplo, la llamada al método constructor puede ser utilizada como parte de una expresión. Los valores de los parámetros que se pasan al constructor cuando se hace la llamada, son asignados a los atributos del objeto que está siendo creado. Si la llamada es al método constructor que incorpora Oracle por defecto, debes indicar un parámetro para cada atributo, en el mismo orden en que están declarados los atributos. Ten en cuenta que los atributos, en contra de lo que ocurre con variables y constantes, no pueden tener valores por defecto asignados en su declaración. Por tanto, los valores que se desee que tengan inicialmente los atributos de un objeto instanciado deben indicarse como parámetros en la llamada al método constructor. Existe la posibilidad de utilizar los nombres de los parámetros formales en la llamada al método constructor, en lugar de utilizar el modelo posicional de los parámetros. De esta manera no es obligatorio respetar el orden en el que se encuentran los parámetros reales respecto a los parámetros formales, que como se ha comentado antes coincide con el orden de los atributos. DECLARE u1 Usuario; BEGIN u1 := NEW Usuario('user1', -10); /* Se mostrará el crédito como cero, al intentar asignar un crédito negativo */ dbms_output.put_line(u1.credito); END; /

Acceso a los atributos de objetos

Para hacer referencia a un atributo de un objeto debes utilizar el nombre de dicho atributo, utilizando el punto para acceder al valor que contiene o bien para modificarlo. Antes debe ir precedido del objeto cuyo atributo deseas conocer o modificar. nombre_objeto.nombre_atributo Por ejemplo, la consulta del valor de un atributo puede utilizarse como parte de una asignación o como parámetro en la llamada a una función: unNombre := usuario1.nombre; dbms_output.put_line(usuario1.nombre); La modificación del valor contenido en el atributo puede ser similar a la siguiente: usuario1.nombre:= 'Nuevo Nombre'; Los nombres de los atributos pueden ser encadenados, lo que permite el acceso a atributos de tipos de objetos anidados. Por ejemplo, si el objeto sitio1 tiene un atributo del tipo de objeto Usuario, se accedería al atributo del nombre del usuario con: sitio1.usuario1.nombre Si se utiliza en una expresión el acceso a un atributo de un objeto que no ha sido inicializado, se evalúa como NULL . Por otro lado, si se intenta asignar valores a un objeto no inicializado, éste lanza una excepción ACCESS_INTO_NULL . Para comprobar si un objeto es NULL se puede utilizar el operador de comparación IS se obtiene el valor TRUE si es así. NULL con el que De manera similar, al intentar hacer una llamada a un método de un objeto que no ha sido inicializado, se lanza una excepción NULL_SELF_DISPATCH . Si se pasa como parámetro de tipo IN, los atributos del objeto NULL se evalúan como NULL , y si el parámetro es de tipo OUT o IN OUT lanza una excepción al intentar modificar el valor de sus atributos.

Llamada a los métodos de los objetos

Al igual que las llamadas a subprogramas, puedes invocar a los métodos de un tipo de objetos utilizando un punto entre el nombre del objeto y el del método. Los parámetros reales que se pasen al método se indicarán separados por comas, entre paréntesis, después del nombre del método. usuario1.setNombreCompleto('Juan', 'García Fernández'); Si el método no tiene parámetros, se indicará la lista de parámetros reales vacía (sólo con los paréntesis), aunque se pueden omitir los paréntesis. credito := usuario1.getCredito(); Las llamadas a métodos pueden encadenarse, en cuyo caso, el orden de ejecución de los métodos es de derecha a izquierda. Se debe tener en cuenta que el método de la izquierda debe retornar un objeto del tipo correspondiente al método de la derecha. Por ejemplo, si dispones de un objeto sitio1 que tiene declarado un método getUsuario el cual retorna un objeto del tipo Usuario, puedes realizar con ese valor retornado una llamada a un método del tipo de objeto Usuario: sitio1.getUsuario.setNombreCompleto('Juan', 'García Fernández'); Los métodos MEMBER son invocados utilizando una instancia del tipo de objeto: nombre_objeto.metodo() En cambio, los métodos instancias: STATIC se invocan usando el tipo de objeto, en lugar de una de sus nombre_tipo_objeto.metodo()

Herencia

El lenguaje PL/SQL admite la herencia simple de tipos de objetos, mediante la cual, puedes definir subtipos de los tipos de objeto. Estos subtipos, o tipos heredados, contienen todos los atributos y métodos del tipo padre, pero además pueden contener atributos y métodos adicionales, o incluso sobreescribir métodos del tipo padre. Para indicar que un tipo de objeto es heredado de otro hay que usar la palabra reservada UNDER , y además hay que tener en cuenta que el tipo de objeto del que hereda debe tener la propiedad NOT FINAL . Por defecto, los tipos de objeto se declaran como FINAL , es decir, que no se puede crear un tipo de objeto que herede de él. Si no se indica lo contrario, siempre se pueden crear objetos (instancias) de los tipos de objeto declarados. Indicando la opción NOT INSTANTIABLE puedes declarar tipos de objeto de los que no se pueden crear objetos. Estos tipos tendrán la función de ser padres de otros tipos de objeto. En el siguiente ejemplo puedes ver cómo se crea el tipo de objeto Persona, que se utilizará heredado en el tipo de objeto UsuarioPersona. De esta manera, este último tendrá los atributos de Persona - 14 -Desarrollo de Aplicaciones Web Tema 7 más los atributos declarados en UsuarioPersona. En la creación del objeto puedes observar que se deben asignar los valores para todos los atributos, incluyendo los heredados. CREATE TYPE Persona AS OBJECT ( nombre VARCHAR2(20), apellidos VARCHAR2(30) ) NOT FINAL; / CREATE TYPE UsuarioPersona UNDER Persona ( login VARCHAR(30), f_ingreso DATE, credito NUMBER ); / DECLARE u1 UsuarioPersona; BEGIN u1 := NEW UsuarioPersona('nombre1', 'apellidos1', 'user1', '01/01/2001', 100); dbms_output.put_line(u1.nombre); END; /