Continuación de Tutorial OpenXava (1): Empezando, antes de seguir con en este ejemplo te recomendamos que accedas al apartado anterior, donde se explica el proyecto que estamos implementando.
- Objetivo
- Configuración de Tomcat en Eclipse
- Creamos la clase CbCurrency
- Creamos la clase CbCountry (Explicamos @ManyToOne)
- Creamos la clase CbPaymentmethod
- Creamos la clase CbAddresses
- Creamos la clase CbAddress
- Creamos la clase CbEnterprise (@ManyToOne)
- Creamos la clase CbCustomer (Explicamos @OneToOne)
OpenXava (2): Creación del resto de las clases para las tablas
1. Objetivo
En este post vamos a finalizar la creación de las clases para el resto de las tablas del proyecto, nuestro objetivo es finalizar este post con todas las clases cumpliendo su funcionalidad de crear, eliminar y consultar sus datos, manejando todas las relaciones.
La parte de presentación la dejaremos para un siguiente post donde le daremos forma a nuestra pantalla.
Veamos antes de empezar un vídeo del resultado final de la definición de las clases que representan las tablas de la base de datos:
2. Configuración de Tomcat en Eclipse
Antes de empezar vamos a explicar como configurar Tomcat dentro de Eclipse, te recomiendo que lo hagas sino lo has hecho ya por comodidad, en la wiki de OpenXava esta muy bien explicado: Configuración de Tomcat en Eclipse, por lo que solo hago un resumen:
- Vamos a empezar añadiendo añadiendo Tomcat como servidor de ejecución a Eclipse , para ello seleccionamos Windows > Preferences > Server > Runtime Environments y pulsamos el botón Add…
- Escogemos Apache Tomcat v7.0
- Seleccionamos el Tomcat incluido en OpenXava añadiendo la ruta de instalación y finalizamos.
- Ahora vamos a añadir un servidor Tomcat a Eclipse en el menú Window > Show View > Other , siguiendo las instrucciones ya tendrás añadido el servidor.
Listo ya podemos seguir con el proyecto.
3. Creamos la clase CbCurrency
Para hacerlo fácil y comprobar que tenemos todo bien configurado creamos la clase CbCurrency para la tabla cb_currency. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla: @Table(name=»cb_currency»)
- Definimos la clave primaria de la tabla:
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idcurrency", nullable = false) private Integer idcurrency;
- El resto es la definición de las columnas indicando su nombre, tamaño y si pueden ser o no NULL.
- Una vez escrito este código, generamos los getters y setters para todos los valores.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Tabla con las monedas registradas en la aplicación, se podrá relacionar con múltiples tablas. * @author xulescode */ @Entity @Table(name="cb_currency") public class CbCurrency { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idcurrency", nullable = false) private Integer idcurrency; @Required @Column(name = "currency", length = 65, nullable = false) private String currency; @Required @Column(name = "description", length = 255, nullable = false) private String description; @Required @Column(name = "isactive", length = 1, nullable = false) private String isactive; @Required @Column(name = "isocode", length = 3, nullable = false) private String isoCode; @Column(name = "cursymbol", length = 10, nullable = true) private String cursymbol; @Required @Column(name = "precisionstd", length = 10, precision = 0, nullable = false) private java.math.BigDecimal precisionstd; @Required @Column(name = "precisioncost", length = 10, precision = 0, nullable = false) private java.math.BigDecimal precisioncost; @Required @Column(name = "precisionprize", length = 10, precision = 0, nullable = false) private java.math.BigDecimal precisionprize; // Generar getters y setters de todos los campos ... }
Después de introducir solo este código, ya podemos acceder al módulo CbCurrency y probarlo, así de fácil, para esto te recuerdo los pasos ya explicados en el primer post, actualización de la configuración y ejecución en el servidor para hacer las pruebas:
- En nuestro proyecto tenemos una fichero ant de ejecución build.xml con diferentes funcionalidades, nosotros usaremos ahora: desplegarWar.
- Con esto actualizamos el war y podemos ejecutar la aplicación con las últimas actualizaciones.
- Si actualizamos bien la configuración de Eclipse, simplemente encima de nuestro proyecto, en las opciones disponibles seleccionamos: Run As > Run on Server.
Este es el resultado:
4. Creamos la clase CbCountry (Explicamos @ManyToOne)
Para hacerlo fácil y comprobar que tenemos todo bien configurado creamos la clase CbCountry para la tabla cb_country. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla: @Table(name=»cb_country»)
- Definimos la clave primaria de la tabla:
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idcountry", nullable = false) private Integer idcountry;
- Aquí con la nueva propiedad @Hidden indicamos que este campo no se muestra en la presentación de la clase aunque si se utilizará internamente, esto lo hacemos porque este es un campo interno que no tiene significado para el usuario.
- El resto es la definición de las columnas indicando su nombre, tamaño y si pueden ser o no NULL.
- Una vez escrito este código, generamos los getters y setters para todos los valores.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Tabla con los países registrados en la aplicación, se podrá relacionar con múltiples tablas. * @author xulescode */ @Entity @Table(name="cb_country") public class CbCountry { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idcountry", nullable = false) private Integer idcountry; @Required @Column(name = "country", length = 100, nullable = false) private String country; @Column(name = "description", length = 255, nullable = true) private String description; @Required @Column(name = "countrycode", length = 2, nullable = false) private String countrycode; @Required @Column(name = "hasregion", length = 1, nullable = false) private String hasregion; @Column(name = "regionname", length = 60, nullable = true) private String regionname; @Column(name = "expressionphone", length = 20, nullable = true) private String expressionphone; @Required @Column(name = "displaysequence", length = 20, nullable = false) private String displaysequence; @Column(name = "isdefault", length = 1, nullable = true) private String isdefault; @Column(name = "ibannodigits", length = 131089, precision = 0, nullable = true) private java.math.BigDecimal ibannodigits; @Column(name = "ibancountry", length = 2, nullable = true) private String ibancountry; @Required @Column(name = "isactive", nullable = false) private boolean isactive; @ManyToOne @JoinColumn( name = "idcurrency", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_country_idcurrency")) @DescriptionsList private CbCurrency cbCurrency; @ManyToOne @JoinColumn( name = "idlanguage", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_country_idlanguage")) @DescriptionsList private CbLanguage cbLanguage; // Generar getters y setters de todos los campos ... }
Como habrás visto en la clase o si analizaste la relación entre tablas verás que cb_country está relacionado con cb_currency y cb_language, al igual que en la base de datos en la clase también tenemos que definir las relaciones JPA que se utilizan, esto nos será muy útil también en la presentación, ya que en OpenXava gracias a la interpretación de esta configuración JPA y de las anotaciones se nos facilita de forma muy fácil la modificación de la presentación, sin ir más allá aquí utilizaremos @DescriptionList para ver un ejemplo.
La relacion de CbCountry con CbLanguage y CbCurrency es la misma: un pais (CbCountry) puede tener un idioma (CbLanguage) seleccionano uno de todos los que existen, es decir, estamos hablando de una relación de varios a uno (ManyToOne), lo mismo sucede para CbCurrency. Expliquemoslo:
- @ManyToOne
- Anotación JPA con la que definimos la relación de uno a muchos de CbCurrency.
- @JoinColumn( name = «idcurrency», nullable = true, foreignKey = @ForeignKey(name = «fk_cb_country_idcurrency»))
- Con @JoinColumn seguimos con JPA definiendo el nombre de la columna de la base de datos por la que relacionamos estas dos tablas en este caso idcurrency, en nuestro caso como hemos utilizados un nombre específico para la clave foránea lo tenemos que indicar: foreignKey = @ForeignKey(name = «fk_cb_country_idcurrency») donde es el nombre que le hemos dado en la base de datos.
- @DescriptionsList
- Con @DescriptionsList indicamos a OpenXava para que visualice la referencia como una lista de descripciones (combo), cuando el número de valores que usamos no es muy grande esto es muy prácitco, más adelante veremos como podemos filtrar los valores de la selección para que salga un grupo de valores según una condición y no todo el conjunto de idiomas, así como el campo seleccionado en la presentación, pero esto será más adelante, si quieres más información sobre las posibilidades de esta anotación las puedes consultar aquí: OpenXava View: @DescriptionList.
- private CbCurrency cbCurrency;
- En CbCountry creamos una clase CbCurrency que es la que hace referencia dentro de CbCountry a la relación y donde definimos los valores arriba descritos que indican la relación y la presentación.
Para CbLanguage la explicación es la misma como puedes ver en el código de la clase:
@ManyToOne @JoinColumn( name = "idlanguage", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_country_idlanguage")) @DescriptionsList private CbLanguage cbLanguage;
Este es el resultado sin usar @DescriptionList, como verás en la imagen a continuación se despliega todo el contenido de CbCurrency y de CbCountry:
Este es el resultado usando @DescriptionList, como verás a continuación se muestran en un combo los contenidos de CbCurrency y de CbCountry:
5. Creamos la clase CbPaymentmethod
Para hacerlo fácil y comprobar que tenemos todo bien configurado creamos la clase CbPaymentmethod para la tabla cb_paymentmethod. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla:@Table(name=»cb_paymentmethod»)
- Definimos la clave primaria de la tabla:
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idpaymentmethod", nullable = true) private Integer idpaymentmethod;
- Una vez escrito este código, generamos los getters y setters para todos los valores.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Métodos de pago definidos para el cliente u otras entidades. * @author xulescode */ @Entity @Table(name = "cb_paymentmethod") public class CbPaymentmethod { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idpaymentmethod", nullable = true) private Integer idpaymentmethod; @Required @Column(name = "paymentmethod", length = 100, nullable = false) private String paymentmethod; @Column(name = "description", length = 150, nullable = true) private String description; @Column(name = "paymententity", length = 50, nullable = true) private String paymententity; @Column(name = "paymentterms", length = 250, nullable = true) private String paymentterms; // Generar getters y setters de todos los campos ... }
Creamos la clase CbAddresses
Para hacerlo fácil y comprobar que tenemos todo bien configurado creamos la clase CbAddresses para la tabla cb_addresses. En esta primera aproximación lo único que haremos es hacer las definiciones básicas:
- Definir el nombre de la tabla:@Table(name=»cb_addresses»)
- Definimos la clave primaria de la tabla:
@Id @Hidden @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idaddresses", nullable = true) private Integer idaddresses;
- Una vez escrito este código, generamos los getters y setters para todos los valores.
package org.xulescode.customerdb.model; import java.util.*; import javax.persistence.*; import org.openxava.annotations.*; /** * Tabla de registro de las direcciones, se asocian aquí las direcciones que tienen un cliente, cada cliente tendrá un número ilimitado de direcciones con cb_address relacionado mediante cb_addresses (es básicamente una tabla relacional). * @author xulescode */ @Entity @Table(name = "cb_addresses") public class CbAddresses { @Id @Hidden @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idaddresses", nullable = true) private Integer idaddresses; @Hidden @Column(name = "addressesentity", nullable = true) private String addressesentity; @OneToMany( mappedBy = "cbAddressesLocal", // El objeto de CbAddress que almacena la relación cascade = CascadeType.ALL) private Collection<CbAddress> cbAddress = new ArrayList<CbAddress>(); // Generar getters y setters de todos los campos ... }
En este caso vamos a necesitar definir una nueva relación JPA que hasta ahora no utilizamos y es @OneToMany, se usa para definir una asociación multi- valor a una colección de entidades, debido a que la relación que estamos creando es bidireccional (porque existen referencias a ambos lados de la relación ) el elemento de anotación mappedBy debe utilizarse para especificar el campo que existe en la entidad referenciada, que es el dueño de la relación, para finalizar esto, en la clase relacionada CbAddress deberemos crear un variable para esta entidad referenciada (private CbAddresses cbAddressesLocal
) que será del tipo @ManyToOne como veremos a continuación.
En primer lugar analizamos la relación que necesitaremos crear en CbAddress:
@ManyToOne
- Anotación JPA con la que definimos la relación de uno a muchos de CbAddresses.
@JoinColumn(
name = "idaddresses",
nullable = true, f
oreignKey = @ForeignKey(name = "fk_cb_address_idaddresses"))
- Como ya vimos antes usamos la anotación @JoinColumn para especificar la columna implicada y el nombre de la clave foránea utilizada.
private CbAddresses cbAddressesLocal;
- Este es la variable que vamos a tener que referenciar en CbAddresses con el campo mappedBy, es decir, esta es la relación entre CbAddresses y CbAddress que es bidireccional.
Ahora vamos a ocuparnos de la definición @OneToMany en la clase CbAddresses que estamos definiendo:
@OneToMany(
mappedBy = "cbAddressesLocal",
cascade = CascadeType.ALL)
- Anotación JPA con la que definimos una asociación multi- valor a una colección de entidades, debido a que la relación que estamos creando es bidireccional, con
mappedBy = "cbAddressesLocal"
indicamos la entidad utilizada en la otra clase para la relación, es decir, el objeto CbAddress que almacena la relación, después con otros campos comocascade = CascadeType.ALL
podemos especificar el comportamiento de la relación.
- Anotación JPA con la que definimos una asociación multi- valor a una colección de entidades, debido a que la relación que estamos creando es bidireccional, con
private Collection<CbAddress> cbAddress = new ArrayList<CbAddress>();
- Variable con la que definimos CbAddress dentro de CbAddresses.
Cuando definamos CbCustormer, podremos ver más claramente cual es el objetivo de la creación de esta entidad, y su uso.
7. Creamos la clase CbAddress
Creamos la clase CbAddress para la tabla cb_address. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla:
@Table(name="cb_address")
- Definimos la clave primaria de la tabla:
- El resto es la definición de las columnas indicando su nombre, tamaño y si pueden ser o no NULL.
- Una vez escrito este código, generamos los getters y setters para todos los valores.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Tabla de dirección donde se guardan los datos de la dirección en sí. * @author xulescode */ @Entity @Table(name="cb_address") public class CbAddress { @ManyToOne @JoinColumn( name = "idaddresses", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_address_idaddresses")) private CbAddresses cbAddressesLocal; // Esta es la relación entre CbAddresses y CbAddress que es bidireccional. @Id @Hidden @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idaddress", nullable = true) private Integer idaddress; @Column(name = "address", nullable = true) private String address; @Column(name = "postalnumber", length = 20, nullable = true) private String postalnumber; @Column(name = "mainphone", length = 50, nullable = true) private String mainphone; @Column(name = "movilephone", length = 50, nullable = true) private String movilephone; @Column(name = "phone2", length = 50, nullable = true) private String phone2; @Column(name = "phone3", length = 50, nullable = true) private String phone3; @Column(name = "carrier", length = 200, nullable = true) private String carrier; @Column(name = "addresstype", length = 100, nullable = true) private String addresstype; @Column(name = "locality", length = 250, nullable = true) private String locality; @Column(name = "state", length = 250, nullable = true) private String state; @Column(name = "notes1", length = 500, nullable = true) private String notes1; @ManyToOne @JoinColumn( name = "idcountry", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_address_idcountry")) @DescriptionsList(descriptionProperties = "country") private CbCountry cbCountry; // Generar getters y setters de todos los campos ... }
La relacion de CbCountry con CbLanguage y CbCurrency es la misma: un pais (CbCountry) puede tener un idioma (CbLanguage) seleccionano uno de todos los que existen, es decir, estamos hablando de una relación de varios a uno (ManyToOne), lo mismo sucede para CbCurrency. Expliquemoslo:
@ManyToOne
- Anotación JPA con la que definimos la relación de uno a muchos de CbCountry.
@JoinColumn( name = "
idcountry
", nullable = true, foreignKey =@ForeignKey(name = "fk_cb_address_idcountry")
- Con
@JoinColumn
seguimos con JPA definiendo el nombre de la columna de la base de datos por la que relacionamos estas dos tablas en este caso idcountry, en nuestro caso como hemos utilizados un nombre específico para la clave foránea lo tenemos que indicar:foreignKey = @ForeignKey(name = "fk_cb_address_idcountry"))
donde es el nombre que le hemos dado en la base de datos.
- Con
@DescriptionsList(descriptionProperties = "country")
- Con @DescriptionsList indicamos que queremos usar un combo, ahora podemos ver como se puede indicar que campo usamos en el combo, esto lo conseguimos con la propiedad descriptionProperties al indicar la columna que usamos de CbCountry en este caso country.
private CbCountry cbCountry;
- En CbAddress creamos la clase CbCountry que es la que hace referencia dentro de CbAddress a la relación y donde definimos los valores arriba descritos que indican la relación y la presentación.
Cuando definamos CbCustormer, podremos ver más claramente cual es el objetivo de la creación de esta entidad, y su uso. En este caso ya podemos ver una imagen de su presentacion, este es el resultado:
- Listado de la direcciones creadas en la aplicación:
- Veamos como se muestran los datos si seleccionamos una dirección:
8. Creamos la clase CbEnterprise (@ManyToOne)
Creamos la clase CbEnterprise para la tabla cb_enterprise asociamos la clase con la tabla y definimos la clave primaria:
- Definir el nombre de la tabla:
@Table(name="cb_enterprise")
- Definimos la clave primaria de la tabla:
@Id
@Required
@Column(name = "identerprise", nullable = true)
private Integer identerprise;
- Definimos los campos explicados en el esquema para la tabla empresa, y finalmente, después de definir las relaciones generamos los getters y setters.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Empresas de la aplicación, cada empresa tendrá sus clientes. * @author xulescode */ @Entity @Table(name = "cb_enterprise") public class CbEnterprise { @Id @Required @Column(name = "identerprise", nullable = true) private Integer identerprise; @Column(name = "enterprise", length = 150, nullable = true) private String name; @Column(name = "description", length = 250, nullable = true) private String description; @Column(name = "enterprisealias", length = 100, nullable = true) private String enterprisealias; @Column(name = "contact", length = 250, nullable = true) private String contact; @Column(name = "state", length = 30, nullable = true) private String state; @Column(name = "balance", length = 10, precision = 3, nullable = true) private java.math.BigDecimal balance; @Column(name = "ei", length = 100, nullable = true) private String ei; @Column(name = "enterprisepayer", length = 20, nullable = true) private String enterprisepayer; @ManyToOne @JoinColumn( name = "idcurrency", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_enterprise_idcurrency")) @DescriptionsList private CbCurrency cbCurrency; @ManyToOne @JoinColumn( name = "idlanguage", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_enterprise_idlanguage")) @DescriptionsList private CbLanguage cbLanguage; @ManyToOne @JoinColumn( name = "idcountry", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_enterprise_idcountry")) @DescriptionsList private CbCountry cbCountry; // Generar getters y setters de todos los campos ... }
Creamos la clase CbCustomer (Explicamos @OneToOne)
Para hacerlo fácil y comprobar que tenemos todo bien configurado creamos la clase CbCustomer para la tabla cb_customer. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla:
@Table(name="cb_customer")
- Definimos la clave primaria de la tabla:
@Id
@Required
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "idcustomer", nullable = true)
private Integer idcustomer;
- Definimos los campos explicados en el esquema para la tabla empresa, y finalmente, después de definir las relaciones generamos los getters y setters.
- Échale un vistazo a la clase, después explicamos las relaciones implementadas.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Tabla general de cliente. Tabla donde se almacenarán los clientes de las diferentes empresas, se entiende cliente como aquel que compra a una empresa. * @author xulescode */ @Entity @Table(name = "cb_customer") public class CbCustomer { @Id @Required @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idcustomer", nullable = true) private Integer idcustomer; @Column(name = "customer", length = 15, nullable = true) private String customer; @Column(name = "customername", length = 150, nullable = true) private String customername; @Column(name = "customeralias", length = 100, nullable = true) private String customeralias; @Column(name = "contact", length = 250, nullable = true) private String contact; @Column(name = "customerstate", length = 30, nullable = true) private String customerstate; @Column(name = "sale", length = 10, precision = 3, nullable = true) private java.math.BigDecimal sale; @Column(name = "identitynumber", length = 50, nullable = true) private String identitynumber; @Column(name = "customerpayer", length = 20, nullable = true) private String customerpayer; @ManyToOne @JoinColumn( name = "identerprise", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_identerprise")) @DescriptionsList private CbEnterprise cbEnterprise; @ManyToOne @JoinColumn( name = "idcurrency", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idcurrency")) @DescriptionsList private CbCurrency cbCurrency; @ManyToOne @JoinColumn( name = "idlanguage", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idlanguage")) @DescriptionsList private CbLanguage cbLanguage; @ManyToOne @JoinColumn( name = "idcountry", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idcountry")) @DescriptionsList private CbCountry cbCountry; @ManyToOne @JoinColumn( name = "idpaymentmethod", nullable = true, foreignKey = @ForeignKey(name = "cb_customers_idpaymentmethod")) @DescriptionsList(descriptionProperties = "paymentmethod") private CbPaymentmethod cbPaymentmethod; @OneToOne @JoinColumn( name = "idaddresses", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idaddresses")) @AsEmbedded private CbAddresses cbAddresses; // Generar getters y setters de todos los campos ... }
En el caso de CbCustomer vamos a definir tres relaciones como se puede ver en la definición de la clase anteriormente descrita, y son las siguientes.
- Definimos la moneda del cliente (CbCustomer) mediante CbCurrency , esta es una relación de muchos a uno que definimos así:
@ManyToOne @JoinColumn( name = "idcurrency", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idcurrency")) @DescriptionsList private CbCurrency cbCurrency;
- Definimos un único idioma para la empresa (CbCustomer) mediante CbLanguage, esta es una relación de muchos a uno que definimos así:
@ManyToOne @JoinColumn( name = "idlanguage", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idlanguage"))</code> @DescriptionsList</code> private CbLanguage cbLanguage;
- Definimos un único país del cliente (CbCustomer) mediante CbCountry, esta es una relación de muchos a uno, en este caso el país (CbCountry) podrá tener una moneda e idioma diferente al que tenga la empresa, que definimos así:
@ManyToOne @JoinColumn( name = "idcountry", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idcountry")) @DescriptionsList private CbCountry cbCountry;
- Definimos el método de pago del cliente (CbCustomer) mediante CbLanguage, esta es una relación de muchos a uno que definimos así:
@ManyToOne @JoinColumn( name = "idpaymentmethod", nullable = true, foreignKey = @ForeignKey(name = "cb_customers_idpaymentmethod")) @DescriptionsList(descriptionProperties = "paymentmethod") private CbPaymentmethod cbPaymentmethod;
- Definimos las direcciones del cliente (CbCustomer) que queremos que tenga, una o varias por ello utilizamos las tablas cb_addresses que nos sirve para agrupar las direcciones del cliente y cb_address donde definimos la dirección en sí y que serán las del cliente con la relación que establecemos usando CbAddresses y CbAddress respectivamente, veamos como:
@OneToOne
- Define un solo valor de asociación a otra entidad que tiene como multiplicidad uno a uno. Si la relación fuese bidireccional (que no es el caso) utilizaríamos mappedBy para completar la definición.
@JoinColumn(
name = "idaddresses",
nullable = true,
foreignKey = @ForeignKey(name = "fk_cb_customer_idaddresses"))
- Como ya explicamos antes definimos la columna implicada en la clave foránea y el nombre que utilizamos para la clave.
private CbAddresses cbAddresses;
- Definición de la variable para definir la relación. En el siguiente post donde mejoramos la presentación para incrustar las direcciones directamente haciendo CbAddresses transparente para el usuario. En las imágenes del final puedes ver la presentación de las direcciones.
- Y por último definimos la empresa a la que se asigna el cliente, con lo que en nuestro proyecto una empresa podrá tener uno o varios cliente, y cada cliente podrá pertenecer únicamente a una empresa:
@ManyToOne @JoinColumn( name = "identerprise", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_identerprise")) @DescriptionsList private CbEnterprise cbEnterprise;
Veamos algunas imágenes de CbCustomer:
- Lista de los clientes, en este caso solo tenemos uno creado:
- Modo edición del cliente seleccionado, donde puedes ver todas las clases que hemos relacionado: CbEnterprise, CbCurrency, CbLanguage, CbCountry, CbPaymentmethod y CbAddresess:
- Detalle de las direcciones del cliente, puedes como aparecen representadas las dos clases utilizadas: CbAddresses y CbAddress. Desde aquí podemos añadire nuevas direcciones o cambiar por completo la CbAddresses asociada al cliente (esto no es correcto y veremos como mejorarlo en el siguiente post).
Hasta aquí el segundo post del tutorial OpenXava, en el siguiente post adaptaremos la presentación utilizando todas las utilidades que nos da OpenXava mediante las anotaciones y otras implementaciones.
Espero que te haya sido útil
Continuación del tutorial: Tutorial Openxava (3.1): Actualizando la presentación con View
La anotación @View se puede usar en una entidad o una clase incrustable para definir la disposición de sus miembros en la interfaz de usuario.
OpenXava
Vamos a ver como configuramos los formularios en OpenXava, como modificamos los campos utilizados y otras propiedades. Para ello en este capítulo vamos a estudiar con nuestro proyecto: las vistas (Views), los estereotipos (Stereotype) y la internacionalización (i18n), además de otras cosas.
Continuación de Tutorial OpenXava (1): Empezando, antes de seguir con en este ejemplo te recomendamos que accedas al apartado anterior, donde se explica el proyecto que estamos implementando.
Objetivo
En este post vamos a finalizar la creación de las clases para el resto de las tablas del proyecto, nuestro objetivo es finalizar este post con todas las clases cumpliendo su funcionalidad de crear, eliminar y consultar sus datos, manejando todas las relaciones.
La parte de presentación la dejaremos para un siguiente post donde le daremos forma a nuestra pantalla.
Veamos antes de empezar un vídeo del resultado final de la definición de las clases que representan las tablas de la base de datos:
Configuración de Tomcat en Eclipse
Antes de empezar vamos a explicar como configurar Tomcat dentro de Eclipse, te recomiendo que lo hagas sino lo has hecho ya por comodidad, en la wiki de OpenXava esta muy bien explicado: Configuración de Tomcat en Eclipse, por lo que solo hago un resumen:
- Vamos a empezar añadiendo añadiendo Tomcat como servidor de ejecución a Eclipse , para ello seleccionamos Windows > Preferences > Server > Runtime Environments y pulsamos el botón Add…
- Escogemos Apache Tomcat v7.0
- Seleccionamos el Tomcat incluido en OpenXava añadiendo la ruta de instalación y finalizamos.
- Ahora vamos a añadir un servidor Tomcat a Eclipse en el menú Window > Show View > Other , siguiendo las instrucciones ya tendrás añadido el servidor.
Listo ya podemos seguir con el proyecto.
Creamos la clase CbCurrency para la tabla cb_currency
Para hacerlo fácil y comprobar que tenemos todo bien configurado creamos la clase CbCurrency para la tabla cb_currency. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla: @Table(name=»cb_currency»)
- Definimos la clave primaria de la tabla:
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idcurrency", nullable = false) private Integer idcurrency;
- El resto es la definición de las columnas indicando su nombre, tamaño y si pueden ser o no NULL.
- Una vez escrito este código, generamos los getters y setters para todos los valores.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Tabla con las monedas registradas en la aplicación, se podrá relacionar con múltiples tablas. * @author xulescode */ @Entity @Table(name="cb_currency") public class CbCurrency { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idcurrency", nullable = false) private Integer idcurrency; @Required @Column(name = "currency", length = 65, nullable = false) private String currency; @Required @Column(name = "description", length = 255, nullable = false) private String description; @Required @Column(name = "isactive", length = 1, nullable = false) private String isactive; @Required @Column(name = "isocode", length = 3, nullable = false) private String isoCode; @Column(name = "cursymbol", length = 10, nullable = true) private String cursymbol; @Required @Column(name = "precisionstd", length = 10, precision = 0, nullable = false) private java.math.BigDecimal precisionstd; @Required @Column(name = "precisioncost", length = 10, precision = 0, nullable = false) private java.math.BigDecimal precisioncost; @Required @Column(name = "precisionprize", length = 10, precision = 0, nullable = false) private java.math.BigDecimal precisionprize; // Generar getters y setters de todos los campos ... }
Después de introducir solo este código, ya podemos acceder al módulo CbCurrency y probarlo, así de fácil, para esto te recuerdo los pasos ya explicados en el primer post, actualización de la configuración y ejecución en el servidor para hacer las pruebas:
- En nuestro proyecto tenemos una fichero ant de ejecución build.xml con diferentes funcionalidades, nosotros usaremos ahora: desplegarWar.
- Con esto actualizamos el war y podemos ejecutar la aplicación con las últimas actualizaciones.
- Si actualizamos bien la configuración de Eclipse, simplemente encima de nuestro proyecto, en las opciones disponibles seleccionamos: Run As > Run on Server.
Este es el resultado:
Creamos la clase CbCountry para la tabla cb_country
Para hacerlo fácil y comprobar que tenemos todo bien configurado creamos la clase CbCountry para la tabla cb_country. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla: @Table(name=»cb_country»)
- Definimos la clave primaria de la tabla:
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idcountry", nullable = false) private Integer idcountry;
- Aquí con la nueva propiedad @Hidden indicamos que este campo no se muestra en la presentación de la clase aunque si se utilizará internamente, esto lo hacemos porque este es un campo interno que no tiene significado para el usuario.
- El resto es la definición de las columnas indicando su nombre, tamaño y si pueden ser o no NULL.
- Una vez escrito este código, generamos los getters y setters para todos los valores.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Tabla con los países registrados en la aplicación, se podrá relacionar con múltiples tablas. * @author xulescode */ @Entity @Table(name="cb_country") public class CbCountry { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idcountry", nullable = false) private Integer idcountry; @Required @Column(name = "country", length = 100, nullable = false) private String country; @Column(name = "description", length = 255, nullable = true) private String description; @Required @Column(name = "countrycode", length = 2, nullable = false) private String countrycode; @Required @Column(name = "hasregion", length = 1, nullable = false) private String hasregion; @Column(name = "regionname", length = 60, nullable = true) private String regionname; @Column(name = "expressionphone", length = 20, nullable = true) private String expressionphone; @Required @Column(name = "displaysequence", length = 20, nullable = false) private String displaysequence; @Column(name = "isdefault", length = 1, nullable = true) private String isdefault; @Column(name = "ibannodigits", length = 131089, precision = 0, nullable = true) private java.math.BigDecimal ibannodigits; @Column(name = "ibancountry", length = 2, nullable = true) private String ibancountry; @Required @Column(name = "isactive", nullable = false) private boolean isactive; @ManyToOne @JoinColumn( name = "idcurrency", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_country_idcurrency")) @DescriptionsList private CbCurrency cbCurrency; @ManyToOne @JoinColumn( name = "idlanguage", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_country_idlanguage")) @DescriptionsList private CbLanguage cbLanguage; // Generar getters y setters de todos los campos ... }
Como habrás visto en la clase o si analizaste la relación entre tablas verás que cb_country está relacionado con cb_currency y cb_language, al igual que en la base de datos en la clase también tenemos que definir las relaciones JPA que se utilizan, esto nos será muy útil también en la presentación, ya que en OpenXava gracias a la interpretación de esta configuración JPA y de las anotaciones se nos facilita de forma muy fácil la modificación de la presentación, sin ir más allá aquí utilizaremos @DescriptionList para ver un ejemplo.
La relacion de CbCountry con CbLanguage y CbCurrency es la misma: un pais (CbCountry) puede tener un idioma (CbLanguage) seleccionano uno de todos los que existen, es decir, estamos hablando de una relación de varios a uno (ManyToOne), lo mismo sucede para CbCurrency. Expliquemoslo:
- @ManyToOne
- Anotación JPA con la que definimos la relación de uno a muchos de CbCurrency.
- @JoinColumn( name = «idcurrency», nullable = true, foreignKey = @ForeignKey(name = «fk_cb_country_idcurrency»))
- Con @JoinColumn seguimos con JPA definiendo el nombre de la columna de la base de datos por la que relacionamos estas dos tablas en este caso idcurrency, en nuestro caso como hemos utilizados un nombre específico para la clave foránea lo tenemos que indicar: foreignKey = @ForeignKey(name = «fk_cb_country_idcurrency») donde es el nombre que le hemos dado en la base de datos.
- @DescriptionsList
- Con @DescriptionsList indicamos a OpenXava para que visualice la referencia como una lista de descripciones (combo), cuando el número de valores que usamos no es muy grande esto es muy prácitco, más adelante veremos como podemos filtrar los valores de la selección para que salga un grupo de valores según una condición y no todo el conjunto de idiomas, así como el campo seleccionado en la presentación, pero esto será más adelante, si quieres más información sobre las posibilidades de esta anotación las puedes consultar aquí: OpenXava View: @DescriptionList.
- private CbCurrency cbCurrency;
- En CbCountry creamos una clase CbCurrency que es la que hace referencia dentro de CbCountry a la relación y donde definimos los valores arriba descritos que indican la relación y la presentación.
Para CbLanguage la explicación es la misma como puedes ver en el código de la clase:
@ManyToOne @JoinColumn( name = "idlanguage", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_country_idlanguage")) @DescriptionsList private CbLanguage cbLanguage;
Este es el resultado sin usar @DescriptionList, como verás en la imagen a continuación se despliega todo el contenido de CbCurrency y de CbCountry:
Este es el resultado usando @DescriptionList, como verás a continuación se muestran en un combo los contenidos de CbCurrency y de CbCountry:
Creamos la clase CbPaymentmethod para la tabla cb_paymentmethod
Para hacerlo fácil y comprobar que tenemos todo bien configurado creamos la clase CbPaymentmethod para la tabla cb_paymentmethod. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla:@Table(name=»cb_paymentmethod»)
- Definimos la clave primaria de la tabla:
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idpaymentmethod", nullable = true) private Integer idpaymentmethod;
- Una vez escrito este código, generamos los getters y setters para todos los valores.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Métodos de pago definidos para el cliente u otras entidades. * @author xulescode */ @Entity @Table(name = "cb_paymentmethod") public class CbPaymentmethod { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idpaymentmethod", nullable = true) private Integer idpaymentmethod; @Required @Column(name = "paymentmethod", length = 100, nullable = false) private String paymentmethod; @Column(name = "description", length = 150, nullable = true) private String description; @Column(name = "paymententity", length = 50, nullable = true) private String paymententity; @Column(name = "paymentterms", length = 250, nullable = true) private String paymentterms; // Generar getters y setters de todos los campos ... }
Creamos la clase CbAddresses para la tabla cb_addresses
Para hacerlo fácil y comprobar que tenemos todo bien configurado creamos la clase CbAddresses para la tabla cb_addresses. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla:@Table(name=»cb_addresses»)
- Definimos la clave primaria de la tabla:
@Id @Hidden @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idaddresses", nullable = true) private Integer idaddresses;
- Una vez escrito este código, generamos los getters y setters para todos los valores.
package org.xulescode.customerdb.model; import java.util.*; import javax.persistence.*; import org.openxava.annotations.*; /** * Tabla de registro de las direcciones, se asocian aquí las direcciones que tienen un cliente, cada cliente tendrá un número ilimitado de direcciones con cb_address relacionado mediante cb_addresses (es básicamente una tabla relacional). * @author xulescode */ @Entity @Table(name = "cb_addresses") public class CbAddresses { @Id @Hidden @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "idaddresses", nullable = true) private Integer idaddresses; @Hidden @Column(name = "addressesentity", nullable = true) private String addressesentity; @OneToMany( mappedBy = "cbAddressesLocal", // El objeto de CbAddress que almacena la relación cascade = CascadeType.ALL) private Collection<CbAddress> cbAddress = new ArrayList<CbAddress>(); // Generar getters y setters de todos los campos ... }
En este caso vamos a necesitar definir una nueva relación JPA que hasta ahora no utilizamos y es @OneToMany, se usa para definir una asociación multi- valor a una colección de entidades, debido a que la relación que estamos creando es bidireccional (porque existen referencias a ambos lados de la relación ) el elemento de anotación mappedBy debe utilizarse para especificar el campo que existe en la entidad referenciada, que es el dueño de la relación, para finalizar esto, en la clase relacionada CbAddress deberemos crear un variable para esta entidad referenciada (private CbAddresses cbAddressesLocal
) que será del tipo @ManyToOne como veremos a continuación.
En primer lugar analizamos la relación que necesitaremos crear en CbAddress:
@ManyToOne
- Anotación JPA con la que definimos la relación de uno a muchos de CbAddresses.
@JoinColumn(
name = "idaddresses",
nullable = true, f
oreignKey = @ForeignKey(name = "fk_cb_address_idaddresses"))
- Como ya vimos antes usamos la anotación @JoinColumn para especificar la columna implicada y el nombre de la clave foránea utilizada.
private CbAddresses cbAddressesLocal;
- Este es la variable que vamos a tener que referenciar en CbAddresses con el campo mappedBy, es decir, esta es la relación entre CbAddresses y CbAddress que es bidireccional.
Ahora vamos a ocuparnos de la definición @OneToMany en la clase CbAddresses que estamos definiendo:
@OneToMany(
mappedBy = "cbAddressesLocal",
cascade = CascadeType.ALL)
- Anotación JPA con la que definimos una asociación multi- valor a una colección de entidades, debido a que la relación que estamos creando es bidireccional, con
mappedBy = "cbAddressesLocal"
indicamos la entidad utilizada en la otra clase para la relación, es decir, el objeto CbAddress que almacena la relación, después con otros campos comocascade = CascadeType.ALL
podemos especificar el comportamiento de la relación.
- Anotación JPA con la que definimos una asociación multi- valor a una colección de entidades, debido a que la relación que estamos creando es bidireccional, con
private Collection<CbAddress> cbAddress = new ArrayList<CbAddress>();
- Variable con la que definimos CbAddress dentro de CbAddresses.
Cuando definamos CbCustormer, podremos ver más claramente cual es el objetivo de la creación de esta entidad, y su uso.
Creamos la clase CbAddress para la tabla cb_address
Creamos la clase CbAddress para la tabla cb_address. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla:
@Table(name="cb_address")
- Definimos la clave primaria de la tabla:
- El resto es la definición de las columnas indicando su nombre, tamaño y si pueden ser o no NULL.
- Una vez escrito este código, generamos los getters y setters para todos los valores.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Tabla de dirección donde se guardan los datos de la dirección en sí. * @author xulescode */ @Entity @Table(name="cb_address") public class CbAddress { @ManyToOne @JoinColumn( name = "idaddresses", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_address_idaddresses")) private CbAddresses cbAddressesLocal; // Esta es la relación entre CbAddresses y CbAddress que es bidireccional. @Id @Hidden @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idaddress", nullable = true) private Integer idaddress; @Column(name = "address", nullable = true) private String address; @Column(name = "postalnumber", length = 20, nullable = true) private String postalnumber; @Column(name = "mainphone", length = 50, nullable = true) private String mainphone; @Column(name = "movilephone", length = 50, nullable = true) private String movilephone; @Column(name = "phone2", length = 50, nullable = true) private String phone2; @Column(name = "phone3", length = 50, nullable = true) private String phone3; @Column(name = "carrier", length = 200, nullable = true) private String carrier; @Column(name = "addresstype", length = 100, nullable = true) private String addresstype; @Column(name = "locality", length = 250, nullable = true) private String locality; @Column(name = "state", length = 250, nullable = true) private String state; @Column(name = "notes1", length = 500, nullable = true) private String notes1; @ManyToOne @JoinColumn( name = "idcountry", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_address_idcountry")) @DescriptionsList(descriptionProperties = "country") private CbCountry cbCountry; // Generar getters y setters de todos los campos ... }
La relacion de CbCountry con CbLanguage y CbCurrency es la misma: un pais (CbCountry) puede tener un idioma (CbLanguage) seleccionano uno de todos los que existen, es decir, estamos hablando de una relación de varios a uno (ManyToOne), lo mismo sucede para CbCurrency. Expliquemoslo:
@ManyToOne
- Anotación JPA con la que definimos la relación de uno a muchos de CbCountry.
@JoinColumn( name = "
idcountry
", nullable = true, foreignKey =@ForeignKey(name = "fk_cb_address_idcountry")
- Con
@JoinColumn
seguimos con JPA definiendo el nombre de la columna de la base de datos por la que relacionamos estas dos tablas en este caso idcountry, en nuestro caso como hemos utilizados un nombre específico para la clave foránea lo tenemos que indicar:foreignKey = @ForeignKey(name = "fk_cb_address_idcountry"))
donde es el nombre que le hemos dado en la base de datos.
- Con
@DescriptionsList(descriptionProperties = "country")
- Con @DescriptionsList indicamos que queremos usar un combo, ahora podemos ver como se puede indicar que campo usamos en el combo, esto lo conseguimos con la propiedad descriptionProperties al indicar la columna que usamos de CbCountry en este caso country.
private CbCountry cbCountry;
- En CbAddress creamos la clase CbCountry que es la que hace referencia dentro de CbAddress a la relación y donde definimos los valores arriba descritos que indican la relación y la presentación.
Cuando definamos CbCustormer, podremos ver más claramente cual es el objetivo de la creación de esta entidad, y su uso. En este caso ya podemos ver una imagen de su presentacion, este es el resultado:
- Listado de la direcciones creadas en la aplicación:
- Veamos como se muestran los datos si seleccionamos una dirección:
Creamos la clase CbEnterprise para la tabla cb_enterprise
Creamos la clase CbEnterprise para la tabla cb_enterprise asociamos la clase con la tabla y definimos la clave primaria:
- Definir el nombre de la tabla:
@Table(name="cb_enterprise")
- Definimos la clave primaria de la tabla:
@Id
@Required
@Column(name = "identerprise", nullable = true)
private Integer identerprise;
- Definimos los campos explicados en el esquema para la tabla empresa, y finalmente, después de definir las relaciones generamos los getters y setters.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Empresas de la aplicación, cada empresa tendrá sus clientes. * @author xulescode */ @Entity @Table(name = "cb_enterprise") public class CbEnterprise { @Id @Required @Column(name = "identerprise", nullable = true) private Integer identerprise; @Column(name = "enterprise", length = 150, nullable = true) private String name; @Column(name = "description", length = 250, nullable = true) private String description; @Column(name = "enterprisealias", length = 100, nullable = true) private String enterprisealias; @Column(name = "contact", length = 250, nullable = true) private String contact; @Column(name = "state", length = 30, nullable = true) private String state; @Column(name = "balance", length = 10, precision = 3, nullable = true) private java.math.BigDecimal balance; @Column(name = "ei", length = 100, nullable = true) private String ei; @Column(name = "enterprisepayer", length = 20, nullable = true) private String enterprisepayer; @ManyToOne @JoinColumn( name = "idcurrency", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_enterprise_idcurrency")) @DescriptionsList private CbCurrency cbCurrency; @ManyToOne @JoinColumn( name = "idlanguage", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_enterprise_idlanguage")) @DescriptionsList private CbLanguage cbLanguage; @ManyToOne @JoinColumn( name = "idcountry", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_enterprise_idcountry")) @DescriptionsList private CbCountry cbCountry; // Generar getters y setters de todos los campos ... }
Creamos la clase CbCustomer para la tabla cb_customer
Para hacerlo fácil y comprobar que tenemos todo bien configurado creamos la clase CbCustomer para la tabla cb_customer. En esta primera aproximación lo único que haremos es hacer las definiciciones básicas:
- Definir el nombre de la tabla:
@Table(name="cb_customer")
- Definimos la clave primaria de la tabla:
@Id
@Required
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "idcustomer", nullable = true)
private Integer idcustomer;
- Definimos los campos explicados en el esquema para la tabla empresa, y finalmente, después de definir las relaciones generamos los getters y setters.
- Échale un vistazo a la clase, después explicamos las relaciones implementadas.
package org.xulescode.customerdb.model; import javax.persistence.*; import org.openxava.annotations.*; /** * Tabla general de cliente. Tabla donde se almacenarán los clientes de las diferentes empresas, se entiende cliente como aquel que compra a una empresa. * @author xulescode */ @Entity @Table(name = "cb_customer") public class CbCustomer { @Id @Required @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name = "idcustomer", nullable = true) private Integer idcustomer; @Column(name = "customer", length = 15, nullable = true) private String customer; @Column(name = "customername", length = 150, nullable = true) private String customername; @Column(name = "customeralias", length = 100, nullable = true) private String customeralias; @Column(name = "contact", length = 250, nullable = true) private String contact; @Column(name = "customerstate", length = 30, nullable = true) private String customerstate; @Column(name = "sale", length = 10, precision = 3, nullable = true) private java.math.BigDecimal sale; @Column(name = "identitynumber", length = 50, nullable = true) private String identitynumber; @Column(name = "customerpayer", length = 20, nullable = true) private String customerpayer; @ManyToOne @JoinColumn( name = "identerprise", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_identerprise")) @DescriptionsList private CbEnterprise cbEnterprise; @ManyToOne @JoinColumn( name = "idcurrency", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idcurrency")) @DescriptionsList private CbCurrency cbCurrency; @ManyToOne @JoinColumn( name = "idlanguage", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idlanguage")) @DescriptionsList private CbLanguage cbLanguage; @ManyToOne @JoinColumn( name = "idcountry", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idcountry")) @DescriptionsList private CbCountry cbCountry; @ManyToOne @JoinColumn( name = "idpaymentmethod", nullable = true, foreignKey = @ForeignKey(name = "cb_customers_idpaymentmethod")) @DescriptionsList(descriptionProperties = "paymentmethod") private CbPaymentmethod cbPaymentmethod; @OneToOne @JoinColumn( name = "idaddresses", nullable = true, foreignKey = @ForeignKey(name = "fk_cb_customer_idaddresses")) @AsEmbedded private CbAddresses cbAddresses; // Generar getters y setters de todos los campos ... }
En el caso de CbCustomer vamos a definir tres relaciones como se puede ver en la definición de la clase anteriormente descrita, y son las siguientes.
- Definimos la moneda del cliente (CbCustomer) mediante CbCurrency , esta es una relación de muchos a uno que definimos así:
@ManyToOne
@JoinColumn(
name = "idcurrency",
nullable = true,
foreignKey = @ForeignKey(name = "fk_cb_customer_idcurrency"))
@DescriptionsList
private CbCurrency cbCurrency;
- Definimos un único idioma para la empresa (CbCustomer) mediante CbLanguage, esta es una relación de muchos a uno que definimos así:
@ManyToOne
@JoinColumn(
name = "idlanguage",
nullable = true,
foreignKey = @ForeignKey(name = "fk_cb_customer_idlanguage"))
@DescriptionsList
private CbLanguage cbLanguage;
- Definimos un único país del cliente (CbCustomer) mediante CbCountry, esta es una relación de muchos a uno, en este caso el país (CbCountry) podrá tener una moneda e idioma diferente al que tenga la empresa, que definimos así:
@ManyToOne
@JoinColumn(
name = "idcountry",
nullable = true,
foreignKey = @ForeignKey(name = "fk_cb_customer_idcountry"))
@DescriptionsList
private CbCountry cbCountry;
- Definimos el método de pago del cliente (CbCustomer) mediante CbLanguage, esta es una relación de muchos a uno que definimos así:
@ManyToOne
@JoinColumn(
name = "idpaymentmethod",
nullable = true,
foreignKey = @ForeignKey(name = "cb_customers_idpaymentmethod"))
@DescriptionsList(descriptionProperties = "paymentmethod")
private CbPaymentmethod cbPaymentmethod;
- Definimos las direcciones del cliente (CbCustomer) que queremos que tenga, una o varias por ello utilizamos las tablas cb_addresses que nos sirve para agrupar las direcciones del cliente y cb_address donde definimos la dirección en sí y que serán las del cliente con la relación que establecemos usando CbAddresses y CbAddress respectivamente, veamos como:
@OneToOne
- Define un solo valor de asociación a otra entidad que tiene como multiplicidad uno a uno. Si la relación fuese bidireccional (que no es el caso) utilizaríamos mappedBy para completar la definición.
@JoinColumn(
name = "idaddresses",
nullable = true,
foreignKey = @ForeignKey(name = "fk_cb_customer_idaddresses"))
- Como ya explicamos antes definimos la columna implicada en la clave foránea y el nombre que utilizamos para la clave.
private CbAddresses cbAddresses;
- Definición de la variable para definir la relación. En el siguiente post donde mejoramos la presentación para incrustar las direcciones directamente haciendo CbAddresses transparente para el usuario. En las imágenes del final puedes ver la presentación de las direcciones.
- Y por último definimos la empresa a la que se asigna el cliente, con lo que en nuestro proyecto una empresa podrá tener uno o varios cliente, y cada cliente podrá pertenecer únicamente a una empresa:
@ManyToOne
@JoinColumn(
name = "identerprise",
nullable = true,
foreignKey = @ForeignKey(name = "fk_cb_customer_identerprise"))
@DescriptionsList
private CbEnterprise cbEnterprise;
Veamos algunas imágenes de CbCustomer:
- Lista de los clientes, en este caso solo tenemos uno creado:
- Modo edición del cliente seleccionado, donde puedes ver todas las clases que hemos relacionado: CbEnterprise, CbCurrency, CbLanguage, CbCountry, CbPaymentmethod y CbAddresess:
- Detalle de las direcciones del cliente, puedes como aparecen representadas las dos clases utilizadas: CbAddresses y CbAddress. Desde aquí podemos añadire nuevas direcciones o cambiar por completo la CbAddresses asociada al cliente (esto no es correcto y veremos como mejorarlo en el siguiente post).
Hasta aquí el segundo post del tutorial OpenXava, en el siguiente post adaptaremos la presentación utilizando todas las utilidades que nos da OpenXava mediante las anotaciones y otras implementaciones.
Buenas tardes.
Tengo un problema. Estoy empezando con Openxava creando dos clases; Paciente y AlergiaNueva. Paciente tiene una colección (relación uno a muchos) de AlergiaNueva. El problema está en que si me meto en paciente, y le doy a añadir nueva alergia me da este error:
Ha sido imposible ejecutar la acción Grabar: org.hibernate.exception.SQLGrammarException: could not execute statement
¿Por qué puede ser?
Clase Paciente:
package org.openxava.cardiologia.model;
import javax.persistence.*;
import org.openxava.annotations.*;
import java.util.*;
@Entity
@Table(name = «paciente»)
public class Paciente {
//PROPIEDADES
@Id // La propiedad numero es la clave. Las claves son obligatorias (required) por defecto
@Column(name=»NUMERONHC», length=6) // La longitud de columna se usa a nivel UI y a nivel DB
private int numeroNhc;
@Column(name=»NOMBRE») // La longitud de columna se usa a nivel UI y a nivel DB
@Required // Se mostrará un error de validación si la propiedad nombre se deja en blanco
private String nombre;
//@Stereotype(«TELEPHONE») //Openxava dispone de un estereotipo para números de teléfonos
@Column(name=»TELEFONO1″)
@Required // Se mostrará un error de validación si la propiedad nombre se deja en blanco
private int telefono1;
//@Stereotype(«TELEPHONE») //Openxava dispone de un estereotipo para números de teléfonos
//@Required // Se mostrará un error de validación si la propiedad nombre se deja en blanco
@Column(name=»TELEFONO2″)
private int telefono2;
@Column(name=»DIRECCION») // La longitud de columna se usa a nivel UI y a nivel DB
@Required // Se mostrará un error de validación si la propiedad nombre se deja en blanco
private String direccion;
@EditAction(«Paciente.editarAlergia»)
@OneToMany (mappedBy=»paciente», cascade=CascadeType.REMOVE)
private Collection alergiasNuevas = new ArrayList();
//MÉTODOS
public int getNumeroNhc() {
return numeroNhc;
}
public void setNumeroNhc(int numeroNhc) {
this.numeroNhc = numeroNhc;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public int getTelefono1() {
return telefono1;
}
public void setTelefono1(int telefono1) {
this.telefono1 = telefono1;
}
public int getTelefono2() {
return telefono2;
}
public void setTelefono2(int telefono2) {
this.telefono2 = telefono2;
}
public String getDireccion() {
return direccion;
}
public void setDireccion(String direccion) {
this.direccion = direccion;
}
public Collection getAlergiasNuevas(){
return alergiasNuevas;
}
public void setAlergiasNuevas(Collection alergiasNuevas) {
this.alergiasNuevas = alergiasNuevas;
}
Clase Alergia Nueva:
package org.openxava.cardiologia.model;
import javax.persistence.*;
import org.openxava.annotations.*;
@Entity
public class AlergiaNueva {
//PROPIEDADES
@Id @Column(name=»IDALERGIA») @Required
private int idAlergia;
@Column(name=»NUMERONHC», length=6) // La longitud de columna se usa a nivel UI y a nivel DB
private int numeroNhc;
@Required
@Column(name=»NUEVAALERGIA»)
private String nuevaAlergia;
//@ReadOnly
//private String userId;
//REFERENCIAS
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(
name=»numeroNhc»,
nullable = true,
foreignKey = @ForeignKey(name = «fkpaciente»)) // fkpaciente es la columna para la clave foránea
@DescriptionsList //Muestra la referencia usando un combo, página OpenXava con ejemplos página 32
private Paciente paciente; // Una referencia Java convencional
//MÉTODOS
public Paciente getPaciente() {
return paciente;
}
public void setPaciente(Paciente paciente) {
this.paciente = paciente;
}
public int getIdAlergia() {
return idAlergia;
}
public void setIdAlergia(int idAlergia) {
this.idAlergia = idAlergia;
}
public int getNumeroNhc() {
return numeroNhc;
}
public void setNumeroNhc(int numeroNhc) {
this.numeroNhc = numeroNhc;
}
public void setNuevaAlergia(String nuevaAlergia) {
this.nuevaAlergia = nuevaAlergia;
}
public String getNuevaAlergia() {
return nuevaAlergia;
}
}
Muchas gracias por su ayuda.
Hola Yaiza.
Vamos a ver si te puedo ayudar, he estado analizando tu código, sin llegar a ejecutarlo el fallo que encuentro es que en la definición de la relacion @OneToMany dentro de tu clase Paciente no has indicado el tipo de colección que estás utilizando (AlergiaNueva), y por eso, el generador de código OpenXava no es capaz de interpretar correctamente tu código, quedaría así:
Espero que con este cambio ya te funcioné correctamente, cuéntame el resultado.
Un saludo.
Buenas tardes Julio. Antes que nada, agradecerte tu tiempo dedicado. Al modificar el texto sigue sucediendo…
Hola Yaiza.
Hoy he podido hacer pruebas con tu ejemplo, y además de lo que te faltaba indicar en alergiasNuevas, al ejecutar tus clases para crear las tablas en la base de datos he visto que en la clase AlergiasNuevas estabas duplicando el campo numeroNhc, tienes que tener en cuenta que este lo puedes obtener con la relación bidireccional que quieres establecer con:
Dicho esto no necesitas repetir el campo numeroNhc en AlergiasNuevas, una vez hechas estas modificaciones el programa me ha funcionado perfectamente, las clases modificadas son estas:
AlergiaNueva.java
Por comodidad he cambiado el nombre del paquete, también puedes ver que ya no aparece el campo numeroNhc, la modificación de la presentación en la web la tendrás que hacer en las anotaciones con OpenXava, puedes modificar las vistas para mostrar los campos que quieras en la web a través de la relación definida en private Paciente paciente; (puedes ver algunos ejemplos en Tutorial Openxava (3.1): Actualizando la presentación con View):
AlergiaNueva.java
En esta clase mantenemos la corrección anterior: private Collection alergiasNuevas = new ArrayList (); , esta sería:
Así a mí me funciona y he introducido datos en una base de datos PostgreSQL de pruebas:



Un saludo.
Exactamente, era ese el problema. ¡Muchíiisimas gracias!!
Gracias por tu ayuda y tiempo.
Saludos.
Genial Yaiza, encantado de haberte ayudado, este tipo de consultas y soluciones pueden ayudar también a otra gente que este empezando, así que gracias por hacer la consulta.
Saludos.
Hola Julio, estoy trabajando con incustaciones he escrito el siguiente código, me ejecuta agrego registros, pero a la hora de editar no me puede mostrar la informacion.
package org.openxava.invoicing.model;
import javax.persistence.*;
import org.openxava.annotations.*;
@Entity
public class Customer {
@Id
@Column(length=6)
private int number;
@Column(length=50)
@Required
private String name;
@Embedded // Así para referenciar a una clase incrustable
private Address address; // Una referencia Java convencional
public Address getAddress() {
if (address == null) address = new Address(); // Así nunca es nulo
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getName() {
return getName();
}
public void setName(String name) {
this.name = name;
}
}