Top Banner
Mapeo de clases Sistemas de persistencia de objetos
102

Mapeo de clases

Feb 09, 2023

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Mapeo de clases

Mapeo de clases

Sistemas de persistencia de objetos

Page 2: Mapeo de clases

Entidades

� Un entidad representa un concepto del dominio

� Puede estar asociada con otras � Puede estar asociada con otras entidades

� Su ciclo de vida es independiente� Debe tener una clave primaria

nov-08 [email protected] 2

Page 3: Mapeo de clases

Value Types

� Representan información adicional, no conceptos principales de dominio

� Se suelen presentar como atributos de � Se suelen presentar como atributos de una entidad o como composiciones (UML)

� Su ciclo de vida depende enteramente de la entidad que las posee

� No pueden tener referencias entrantesnov-08 [email protected] 3

Page 4: Mapeo de clases

VT, no referencias entrantes

nov-08 [email protected] 4

No es posible

Page 5: Mapeo de clases

Representación UML de VT

nov-08 [email protected] 5

equivalentes

Page 6: Mapeo de clases

Representación en Java

nov-08 [email protected] 6

Page 7: Mapeo de clases

Paso de Value Types

� Siempre por copia� En java por defecto se pasan referencias� Problemas al recibir en setters� Problemas al recibir en setters� Cuidado con los getters

� Alternativa: inmutables� Las clases básicas del JDK

� String, Integer, Long, Double, etc

nov-08 [email protected] 7

Page 8: Mapeo de clases

Cuidado en getters

nov-08 [email protected] 8

Peligro!!!

Peligro!!!

Seguro, String es inmutable

Page 9: Mapeo de clases

Getters pueden romper encapsulación

nov-08 [email protected] 9

Page 10: Mapeo de clases

POJO (plain old java objects)

� Las clases que necesitan ser persistentes son clases java planas (java beans)

� Tienen que respetar un mínimo convenio de nombrado

nov-08 [email protected] 10

nombrado� Setters/getters, constructor sin parámetros, etc.

� La información necesaria para persistencia se añade en forma de metadatos� Hibernate nativo � xml, hibernate annotations� JPA � annotations, xml

Page 11: Mapeo de clases

POJO Ejemplo (entidad)

nov-08 [email protected] 11

Page 12: Mapeo de clases

POJO Ejemplo (entidad)

nov-08 [email protected] 12

Page 13: Mapeo de clases

POJO Ejemplo (Value Object)

Tipo de acceso (field,

No lleva @IdNo lleva @Id

nov-08 [email protected] 13

Tipo de acceso (field, property) igual al de la clase que lo incluye

Page 14: Mapeo de clases

POJOs JPA� Constructor sin parámetros obligatorio� Identificador

� Preferiblemente no tipos básicos (int, long, etc.), mejor tipos nullables (Integer, Long, etc.)

� Mejor no claves compuestas

nov-08 [email protected] 14

� Mejor no claves compuestas� Se corresponderán con la clave primaria de la tabla

� Getters y Setters (get/set/is) para cada atributo � pueden ser privados� JPA puede usar los setters al cargar un objeto para ajustar sus atributos

� Colecciones para asociaciones many� Puede ser Set<T>, List<T>, Map<T> o Collection<T>� Setters y getters pueden ser privados

Page 15: Mapeo de clases

Persistencia de campos en JPA� Todos tipos JDK tienen persistencia automática

� Campos de otro tipo:� Referencias a ValueTypes: si son de clases � Referencias a ValueTypes: si son de clases @Embeddable todos los campos a la misma tabla

� Referencias a Entidades: son relaciones, no campos. FK a la tabla de @Entity

� Resto de casos, serialización� Debe implementar Serializable

nov-08 [email protected] 15

Page 16: Mapeo de clases

Metadatos en annotations

� @Entity � entidades� @Embeddable � Value Types� La posición de @Id determina el modo

nov-08 [email protected] 16

� La posición de @Id determina el modo de acceso del motor de persistencia a los atributos� Acceso “field” (public, private, protected, package)� Acceso “properties” (a través de get/set)

� getters y setters public o protected

Page 17: Mapeo de clases

Metadatos en XML

� En fichero orm.xml� En persistence.xml

� Fichero referenciados desde � Fichero referenciados desde persistence.xml

� XML revoca las indicaciones de Annotations� En deploy pueden se pueden ajustar rendimientos sin tocar código fuente

nov-08 [email protected] 17

Page 18: Mapeo de clases

Metadatos xml, ejemplo

nov-08 [email protected] 18

Page 19: Mapeo de clases

Categorías de anotaciones

� Entity� Database Schema� Identity

� Inheritance� Locking� Lifecycle� Identity

� Direct Mappings� Relationshipmappins

� Composition

� Lifecycle� Entity Manager� Queries

nov-08 [email protected] 19

Page 20: Mapeo de clases

Anotaciones por categoría

nov-08 [email protected] 20

Page 21: Mapeo de clases

Anotaciones por categoría

nov-08 [email protected] 21

Page 22: Mapeo de clases

Mapeo de clases

nov-08 [email protected] 22

Page 23: Mapeo de clases

� @Entity� Marca una clase como entidad� Atributo “name” opcional � será el usado

Entidades

nov-08 [email protected] 23

� Atributo “name” opcional � será el usado en las queries

� @Table

Page 24: Mapeo de clases

@Colum

� Condiciona la generación de DDL� Por defecto (sin @Column) cada atributo es un campo en tabla con atributo es un campo en tabla con mismo nombre

nov-08 [email protected] 24

Page 25: Mapeo de clases

@Column, atributos

nov-08 [email protected] 25

@Column, atributos

Page 26: Mapeo de clases

� Marca una clase como ValueType� Se pueden configurar las propiedades (o atributos) con etiquetas:

@Embeddable

(o atributos) con etiquetas:� @Basic, @Column, @Lob, @Temporal, @Enumerated

nov-08 [email protected] 26

Page 27: Mapeo de clases

@Basic

� Aplicable a:

nov-08 [email protected] 27

Page 28: Mapeo de clases

@Enumerated

� Cómo se salvan los valores enumerados� EnumType.ORDINAL� EnumType.STRING

nov-08 [email protected] 28

� EnumType.STRING

En BDD se creará un campo tipo INTEGER o VARCHAR

Page 29: Mapeo de clases

@Temporal

� @Temporal� Matiza el formato final de los campos java.util.Date y java.util.Calendar

nov-08 [email protected] 29

java.util.Date y java.util.Calendar� En la BDD serán DATE, TIME o TIMESTAMP

� Opciones: DATE, TIME, TIMESTAMP

Page 30: Mapeo de clases

@Lob,@Transient

� @Lob

� @Transient

nov-08 [email protected] 30

Page 31: Mapeo de clases

Tabla de tipos hibernate

nov-08 [email protected] 31

Page 32: Mapeo de clases

Tabla de tipos hibernate (2)

nov-08 [email protected] 32

Page 33: Mapeo de clases

Mapeo de clases

nov-08 [email protected] 33

Page 34: Mapeo de clases

Identity vs equality� Java identity� Object equality� Database identity

� a.getId().equals(b.getId())

nov-08 [email protected] 34

� a.getId().equals(b.getId())� clave primaria de la tabla� Se mapean con la etiqueta <id> � Por ello todas las clases todas las clases Entidad Entidad deben tener identificadordeben tener identificador, usualmente un Long

� No siempre serán iguales� El periodo de tiempo que sí lo son se le denomina "Ámbito de identidad garantizada”, ó “Ámbito de persistencia”

Page 35: Mapeo de clases

Identidad de BBDD

nov-08 [email protected] 35

La clave debe ser inmutable, una vez asignada no se puede cambiar

JPA usa el setter cuando se carga en memoria. No debe ser público y no puede ser privado � protected

protected

Page 36: Mapeo de clases

Tipos de claves

� Claves candidatas� Claves naturales� Business keys

nov-08 [email protected] 36

� Business keys� Claves artificiales (subrogadas)

¿Cual es mejor para formar la clave primaria?

Page 37: Mapeo de clases

Clave candidata

� Condiciones� Nunca puede ser NULL� Cada fila es una combinación únicaNunca puede cambiar

nov-08 [email protected] 37

� Nunca puede cambiar� Si hay varias se escogería solo una, las otras son UNIQUE

� Se forman con una sola o combinaciones de propiedades

� Si no hay ninguna está mal el diseño

Page 38: Mapeo de clases

Claves naturales

� Tienen significado en el contexto de uso (para el usuario: las entiende y las maneja)� DNI� Nº de la SS

nov-08 [email protected] 38

� Nº de la SS� La experiencia demuestra que causan problemas a largo plazo si se usan como claves primarias� ¿Siempre son NOT-NULL?� ¿Nunca van a cambiar?� ¿Nunca se van a repetir?

¿Y si nos equivocamos al dar el alta?, luego no se puede cambiar …

Page 39: Mapeo de clases

Business keys

� Podrían ser claves candidatas � Pero existe la probabilidad (baja) de que su valor cambie en el tiempoSon de utilidad para el usuario ya que las

nov-08 [email protected] 39

� Son de utilidad para el usuario ya que las emplea de forma cotidiana� P.e. el nombre del departamento (puede cambiar pero pocas veces)

� No sirven como clave primaria pero tienen su utilidad

Page 40: Mapeo de clases

Claves artificiales (surrogate keys)� Sin significado en el contexto� Siempre generadas por el sistema� Varias estrategias de generación

� AUTO � JPA selecciona según BBDD

nov-08 [email protected] 40

� AUTO � JPA selecciona según BBDD� IDENTITY� SEQUENCE� TABLE� hi/lo� uuid.hex� Nuevas implementando un interfaz

generan int, long o short

genera string de 32 caracteres único en el mundo

Ver documentación de referencia

JPA

Hib

Page 41: Mapeo de clases

Estrategia recomendable

� Usar siempresiempre claves artificiales como claves primarias� Excepto en el caso de BBDD legacy

nov-08 [email protected] 41

� Tipo Long suele ser suficiente e indexa de forma eficiente

� Las claves candidatas se hacen UNIQUE� Las candidatas (y si no hay, las business keys) son las que se emplean en el equals()

Page 42: Mapeo de clases

@Id

� En cada entidad al menos:� Una @Id� Multiple @Id y una @IdClass para la clase � Multiple @Id y una @IdClass para la clase que forma clave (clave compuesta)

� Una @EmbeddedId

nov-08 [email protected] 42

Page 43: Mapeo de clases

@GeneratedValue

� Indica que la clave no es asignada por el programa sino generada por el sistema. Varias estrategias posiblessistema. Varias estrategias posibles

nov-08 [email protected] 43

Page 44: Mapeo de clases

El problema del equals() y hashCode()

Suponiendo que el hashCode() y el equals() se calculan incluyendo el

nov-08 [email protected] 44

equals() se calculan incluyendo el nombre del usuario

¿ i == ii ?

Page 45: Mapeo de clases

HashCode() y equals()� Los Set() y Map() emplean hasCode() y equals() para insertar y luego localizar los elementos en tablas hash.

� Si cambian atributos después de haber introducido un objeto en Set() o Map() no se volverá a encontrar

nov-08 [email protected] 45

Si cambian atributos después de haber introducido un objeto en Set() o Map() no se volverá a encontrar o se podrán insertar repetidos

� El contrato de uso de Set() y Map() exige que no se cambien los atributos del objeto mientras están en la colección

� ¿Sobre qué atributos hay que definir hashCode() y equals()?

Page 46: Mapeo de clases

HashCode() y equals()

� No se pueden definir sobre las claves artificiales ya que no existen hasta que no se inserta en la BBDDSe generan allí, al hacer el INSERT

nov-08 [email protected] 46

� Se generan allí, al hacer el INSERT� Al final de la transacción

� Se deben definir sobre los atributos que forman una clave candidata o en su defecto sobre una business key

Page 47: Mapeo de clases

Mapeo de clases

nov-08 [email protected] 47

Page 48: Mapeo de clases

Entities vs Value types

� Una de las riquezas de los modelos OO � más clases que tablas

� Entidades son aquellas clases de las

nov-08 [email protected] 48

� Entidades son aquellas clases de las cuales los objetos son relevantes para el usuario� En JPA siempre llevan identificador y deben ajustarse a un convenio de nombres (mínimo)

Page 49: Mapeo de clases

Entities vs Value types� Tipos valor son aquellas clases cuya identidad no es conocida por el usuario, ni le importa� Tienen semántica de composición o directamente aparecen como atributos en los diagramas UMLLas clases JDK (Integer, Long, etc.) son de este tipo

nov-08 [email protected] 49

� Las clases JDK (Integer, Long, etc.) son de este tipo� Su ciclo de vida depende totalmente de la entidad a la que están asignados

� Los objetos Valor sólo tienen referencias entrantes de los objetos que los poseen y no pueden ser compartidos con otros objetos

� La diferencia entre uno y otro es difícil de definir ya que depende del contexto

Page 50: Mapeo de clases

Referencias

� A entidades� Se salvan como claves ajenas

� A value types

nov-08 [email protected] 50

� A value types� Se salvan en la misma tabla excepto si son colecciones (p.e. un usuario tiene varias direcciones)

� Se usa la etiqueta @Embedded

Page 51: Mapeo de clases

Ejemplo

nov-08 [email protected] 51

Page 52: Mapeo de clases

Mapeos

Si hay más de un VT del mismo tipo en una

nov-08 [email protected] 52

Si hay más de un VT del mismo tipo en una entidad hay que forzar los nombres de las columnas ya que si no se repiten en el DDL

Page 53: Mapeo de clases

Mapeo de clases

nov-08 [email protected] 53

Page 54: Mapeo de clases

Estrategias para mapear herencia

� JPA permite 3 � Tabla por cada clase no abstracta

� InheritanceType.TABLE_PER_CLASS

nov-08 [email protected] 54

� InheritanceType.TABLE_PER_CLASS

� Tabla por cada clase� InheritanceType.JOINED

� Tabla única para toda la jerarquía� InheritanceType.SINGLE_TABLE

Page 55: Mapeo de clases

Table per concrete class� Una tabla por cada clase no abstracta� Las propiedades heredadas se repiten en cada tabla� Problemas

� Asociaciones polimórficas (de la superclase) se hacen poniendo la FK en cada tabla

InheritanceType.TABLE_PER_CLASS

nov-08 [email protected] 55

poniendo la FK en cada tabla� Consultas polimórficas son menos eficientes, son varias SELECT o una UNION

� Cambios en la superclase se propagan por todas las tablas� Ventajas

� Cuando sólo se necesitan consultas contra las clases hijas� Recomendable

� Cuando no sea necesario el polimorfismo

Page 56: Mapeo de clases

Table per concrete classSe crea una tabla por cada clase no abstracta

abstracta

nov-08 [email protected] 56

Page 57: Mapeo de clases

Table per concrete class

nov-08 [email protected] 57

Atención: Opcional en JPA, puede que no todos los proveedores JPA la soporten

Page 58: Mapeo de clases

Table per class hierarchy� Todas las clases persisten en una única tabla con la unión de todas las columnas de todas las clases

� Usa un discriminador en cada fila para distinguir el tipoVentajas

InheritanceType.SINGLE_TABLE

nov-08 [email protected] 58

� Ventajas� Es simple y eficiente� Soporta el polimorfismo� Fácil de implementar� Fácil modificar cualquier clase

� Desventaja� Todas las columnas no comunes deben ser nullables� Pueden quedar columnas vacías

Page 59: Mapeo de clases

Table per class hierarchy (2)� Mapeo

� En la clase raiz añadir @DiscriminatorColumn� En cada clase hija añadir @DiscriminatorValue

� Recomendación

nov-08 [email protected] 59

� Recomendación� Si las clases hijas tienen pocas propiedades (se diferencian más en comportamiento) y se necesitan asociaciones polimórficas

� Debería ser tomada como estrategia por defecto

Page 60: Mapeo de clases

Table per class hierarchy (3)

nov-08 [email protected] 60

Page 61: Mapeo de clases

Table per class hierarchy (4)

nov-08 [email protected] 61

@DiscriminatorColumn, @DiscriminatorValueno son necesarios, se toman valores por defecto si no están presentes

Page 62: Mapeo de clases

Table per subclass� Cada clase de la jerarquía tiene su propia tabla� Las relaciones de herencia se resuelven con FK� Cada tabla solo tiene columnas para las propiedades no heredadasVentaja

InheritanceType.JOINED

nov-08 [email protected] 62

� Ventaja� Modelo relacional completamente normalizado� Integridad se mantiene� Soporta polimorfismo� Evoluciona bien

� Desventaja� Si hay que hacer cosas a mano las consultas son mas complicadas

� Para jerarquías muy complejas el rendimiento en consultas puede ser pobre, muchas joins

Page 63: Mapeo de clases

Table per subclass (2)

� Recomendación� Si las clases hijas se diferencian mucho en sus propiedades y tienen muchas

nov-08 [email protected] 63

sus propiedades y tienen muchas� Si se necesita polimorfismo� Cuando los nullables den problemas

Page 64: Mapeo de clases

Table per subclass (3)

nov-08 [email protected] 64

Page 65: Mapeo de clases

Table per subclass (4)

nov-08 [email protected] 65

Page 66: Mapeo de clases

Mapeo de clases

nov-08 [email protected] 66

Page 67: Mapeo de clases

Colecciones de Value Types

� No existen en JPA, solo hibernate� Sets, bags, lists, y maps de value types� Forma estándar (idiom) en hibernate de

nov-08 [email protected] 67

� Forma estándar (idiom) en hibernate de inicializar una colección

Page 68: Mapeo de clases

Forma de inicializar colecciones

Siempre se declara el Interfaz genérico

Siempre se asigna

nov-08 [email protected] 68

Siempre se asigna una clase de implementación compatible con el interfaz

Siempre se inicializan en la declaración, no no en el constructoren el constructor

Page 69: Mapeo de clases

Relación entre colecciones JDK y mapeos hibernate

nov-08 [email protected] 69

Lo más usado para colecciones

Page 70: Mapeo de clases

Mapeo de Set

@Column, @JoinTable opcionales, solo fuerzan nombres de tabla y columna

nov-08 [email protected] 70

tabla y columna

La clave de ITEM_IMAGE es compuesta para evitar duplicados en el mismo ITEM (un set no los admite)

Page 71: Mapeo de clases

Mapeo de List

@Column, @JoinTable opcionales

nov-08 [email protected] 71

Perserva el orden

Page 72: Mapeo de clases

Mapeo de Bag

nov-08 [email protected] 72

Clave artificial para hacer cada fila única (bag permite duplicados)

Page 73: Mapeo de clases

Mapeo de Map

@Column, @JoinTable opcionales

nov-08 [email protected] 73

Guarda las claves del mapa

La clave se forma con ITEM_ID + IMAGENAME, no se permiten duplicados

Page 74: Mapeo de clases

Sorted & ordered cols.

� En hibernate no es lo mismo� Sorted se hace en memoria (JVM) usando interfaz Comparable

nov-08 [email protected] 74

interfaz Comparable

� Ordered se hace en la BBDD con SQL

� Sorted solo aplicable a SortedMap y SortedSet

Page 75: Mapeo de clases

Sorted collections

Solo para Set y Map (se hace en JVM)

nov-08 [email protected] 75

Page 76: Mapeo de clases

Ordered collections

nov-08 [email protected] 76

Para cualquier colección (excepto List()); se hace en la BDD con un order by

Page 77: Mapeo de clases

Colecciones de componentes

nov-08 [email protected] 77

Esta clase debe tener redefinidos hashCode() y equals()

Page 78: Mapeo de clases

Mapeo de clases

nov-08 [email protected] 78

Page 79: Mapeo de clases

No son gestionadas

� Al contrario que en EJB 2.x no son gestionadas

� Un asociación Java es unidireccional, es

nov-08 [email protected] 79

� Un asociación Java es unidireccional, es una referencia

� Hibernate no cambia la semántica de Java

� No es lo mismo de A�B que B�A

Page 80: Mapeo de clases

Asociaciones en Java

Se podría añadir un método

Si la relación es bidireccional siempresiempre hay que establecer la relación en las dos clases

nov-08 [email protected] 80

Se podría añadir un método como este para gestionar de forma cómoda la relación

Page 81: Mapeo de clases

Multiplicidad en JPA

� one-to-one� many-to-many� one-to-many

nov-08 [email protected] 81

� one-to-many� many-to-one

� son direccionales, esta es la inversa de una one-to-many

Page 82: Mapeo de clases

Unidireccional muchos a uno

nov-08 [email protected] 82

Bid siempre debe tener un Item

Page 83: Mapeo de clases

Bidireccional uno a muchos

nov-08 [email protected] 83

Doble actualización

Page 84: Mapeo de clases

La doble actualización

� En java es necesaria pero en SQL la asociación es una foreign key. � Solo se actualiza el campo en una tabla.Hibernate vigila ambos extremos y detecta las

nov-08 [email protected] 84

� Hibernate vigila ambos extremos y detecta las dos modificaciones en Java

� Se producirán dos INSERT o dos UPDATE (según) cuando sólo una es necesaria

� Para evitarlo se marca un extremo conmappedBy=“campo_FK_del_otro_extremo”

Page 85: Mapeo de clases

Propagación en cascada

nov-08 [email protected] 85

Si no hay cascada hay que salvar los dos objetos aunque estén asociados Con cascada basta salvar

al padre (persistencia por alcanzabilidad)

Page 86: Mapeo de clases

Cascada o persistencia transitiva

� Se llama de las dos formas� Se da en las relaciones padre/hijo (los hijos dependen del padre)Se puede especificar por separado el tipo

nov-08 [email protected] 86

� Se puede especificar por separado el tipo cascada deseado para cada asociación

En doc de referencia buscar tipos de cascada “Transitive persistence”

Page 87: Mapeo de clases

Tipos de cascada hibernate

nov-08 [email protected] 87

Page 88: Mapeo de clases

Tipos de cascada JPA

� ALL� MERGE� PERSIST� PERSIST� REFRESH� REMOVE

nov-08 [email protected] 88

Page 89: Mapeo de clases

Cascada delete-orphan

¿No será una composición?

nov-08 [email protected] 89

¿No será una composición?

Page 90: Mapeo de clases

Uno o uno con foreign key

nov-08 [email protected] 90

En la clase que no tiene la FK

Page 91: Mapeo de clases

Uno a uno con la misma clave

� Dos tablas comparten la misma clave� Es clave primaria en las dos� Y además foreign key en una de ellas

nov-08 [email protected] 91

� Y además foreign key en una de ellas

� Problema: solo se genera una clave, la segunda tabla debe esperar a que se genere en la primera� Se usa un generador especial para la segunda

Page 92: Mapeo de clases

Uno a unomisma Clave

Con este generador toma la clave de la otra

nov-08 [email protected] 92

Page 93: Mapeo de clases

Uno a muchos con Bag

� Ya está visto con SET pero se puede hacer con BAG si no se necesita ordenación y se permiten duplicados

nov-08 [email protected] 93

ordenación y se permiten duplicados� Al no tener que garantizar el orden ni vigilar los duplicados no hace falta cargar la colección para hacer las inserciones. Se consigue más eficiencia.

Page 94: Mapeo de clases

Uno a muchos con Bag

nov-08 [email protected] 94

Page 95: Mapeo de clases

Uno a muchos con List� Para mantener el orden en el que fueron insertados � Esto es, no se ordenan después de metidos como en SortedSet (o SortedMap)

No lleva mappedBy=“…”

nov-08 [email protected] 95

No lleva mappedBy=“…”

Dos @JoinColumn

Esto anula actualización de este extremo

Page 96: Mapeo de clases

… a Muchos @OrderBy

nov-08 [email protected] 96

List mantiene en memoria el orden traído de BDD

pero en BDD no se mantiene el orden en el que se insertaron en List

Page 97: Mapeo de clases

Muchos a muchos unidireccional

nov-08 [email protected] 97

Se puede hacer también con List e idBag

Page 98: Mapeo de clases

Muchos a muchos bidireccional

@JoinTable opcional

nov-08 [email protected] 98

Page 99: Mapeo de clases

Mapeo de clases asociativas

nov-08 [email protected] 99

En BDD una muchos a muchos con más columnas

En java es una clase más, mapeada con dos relaciones muchos a uno y clave compuesta

Page 100: Mapeo de clases

Clase asociativa

Clase para la clave compuesta

nov-08 [email protected] 100

Clase asociativa

. . .

Page 101: Mapeo de clases

nov-08 [email protected] 101

Clave compuesta: la clase Id debe cumplir unas condiciones

Page 102: Mapeo de clases

Primary Key Class:

� Es una clase Java (POJO) pública.� Constructor público sin argumentos.� Si hay aceso por get/set deben ser � Si hay aceso por get/set deben ser public o protected.

� Debe ser serializable.� Define equals() and hashCode().

nov-08 [email protected] 102