Cooperator Modeler (2)

Esta página es continuación de Cooperator Modeler. Recomendamos su lectura si no se ha hecho todavía.

Antes de continuar revisando las opciones de Cooperator Modeler, vamos a aclarar algunos conceptos de manera que cuando se usa una palabra u otra, se entienda bien el significado de lo que se quiere expresar.

Agregaciones, Composiciones y Asociaciones

Las agregaciones pueden ser tanto del tipo asociación (objetos que no forman parte de la entidad) o del tipo composición (objetos que son parte, o que componen la entidad)
Cooperator Modeler puede agregar 4 tipos de propiedades que pueden agregarse a una entidad y que no son datos que vienen de la tabla original. Algunas ya la hemos explicado, pero vamos a enumerarlas aquí nuevamente:

xxxString
xxxEntity
xxxCollection
xxxAgregation

xxxString:
Es una propiedad del tipo String, que es el campo descripción de una tabla asociada. Por ejemplo, en la entidad Orders, se tiene la posibilidad de agregar una propiedad llamada CustomersString que contiene el nombre del cliente relacionado con la orden. Esta propiedad es de solo lectura y no puede modificarse. Esto es una asociación. Aprovechamos para decir que la obtención de este campo descripción, tiene muy poco costo a nivel de performance, ya que se ejecuta un JOIN en el motor de bases de datos, por lo que podría considerarse parte de la tabla y no como en los demás casos donde hay recurrir a otros mecanismos, como Lazy Load o Cache por ReadOnly. Su uso es así:

Dim o As Order = OrderMapper.Instance().GetOne(233)
Dim name As String = o.CustomerString

xxxEntity:
Es el mismo tipo de asociación que con xxxString, pero en vez de tener solo un simple string con el nombre del cliente asociado a la orden, tenemos una instancia del objeto Customer directamente. En el código, se puede acceder así..

Dim o As Order = OrderMapper.Instance().GetOne(233)
Dim name As String = o.CustomerEntity.CustomerName

 

Como se explica más abajo, el objeto CustomerEntity, puede cargarse por LazyLoad. Recordamos también que este objeto es un objeto asociado, no es una composición de la entidad Order.
Por favor ahora analicemos detenidamente este código:

Dim c As Customer = CustomerMapper.Instance().GetOne(22)
c.CustomerName = “Paul”
Dim o As Order = OrderMapper.Instace().GetOne(2233)
o.CustomerEntity = c
OrderMapper.Instace().Save(o)

En la primera parte se obtiene un cliente, se le modifica el nombre, luego se obtiene una orden, se le asigna el cliente obtenido a esa orden y finalmente se graba la misma. Pero como el cliente es una asociación y no una composición, esto es: no forma parte de la entidad, en la última línea (Save) no se graban los cambios hechos al cliente. Si se ha grabado la orden con sus detalles y también se ha grabado la asignación del cliente a la orden (Ahora Paul es el propietario de la orden 2233).
Pero si se quieren grabar los cambios hechos al cliente se debe invocar al mapper de cliente, de esta forma:

ClienteMapper.Instance().Save(c)

xxxCollection:
Las xxxCollection si son composiciones y forman parte de la entidad. Siguiendo el mismo ejemplo, OrdersDetailCollection es una composición de Orders, y por lo tanto, cuando se graba una orden también se graba sus detalles. Tengamos en cuenta que es una colección debido que por cada Orden hay varios detalles (Los renglones de la Orden)

xxxAggregation:
Los xxxAggregation también son composiciones, y Cooperator Modeler ofrecerá agregar una Aggregation a una entidad cuando detecta una relación 1 a 1 entre 2 tablas. Se trata exactamente igual que la collection, pero solo contiene un objeto y no una colección.

Nodos del tipo propiedad

Los nodos tipo propiedad, son aquellos nodos hijos de los nodos tipo Objeto/Entidad y sirven para modelar las propiedades de nuestras clases.
Antes de continuar, aclaremos que Cooperator Modeler expone tanto propiedades que se recuperan de las columnas de las tablas, como propiedades que se infieren de las relaciones de las tablas por sus claves foráneas. Si bien Cooperator Modeler expone todas las posibles propiedades que pueda tener una clase, es responsabilidad del desarrollador elegir con buen criterio que propiedad agregar en sus clases y evitar el acoplamiento y el sobredimensionamiento de las mismas. Dicho esto, comenzamos a explorar representa cada opción. Recordamos también que en un mismo acto se modelan tanto las clases del tipo Object como las clases del tipo Entity.
La siguiente imagen muestra lo que se ve en el panel de la derecha cuando se selecciona un nodo del tipo propiedad:

modeler_columnoptions.jpg

CLRType:
Es el tipo CLR con el cual se va a generar la propiedad. Si la propiedad en cuestión representa una columna de la tabla, el tipo es el equivalente en CLR del tipo SQL original. Si la columna es una agregación, el tipo que se generará dependerá de la opción seleccionada en GenerateAsType.

GenerateAs:
Es el nombre con el cual se va a generar la propiedad y permite personalizar las clases sin quedar atado al nombre de la columna.

GenerateAsDescriptionField:
Esta opción, permite definir el campo que será tomado como descripción de una tabla. ¿ Que es el campo descripción ? En pocas palabras podríamos decir que es el campo de texto más representativo de una tabla. En la tabla Customers, debería ser CustomerName, en la tabla Region, RegionDescription, y en la tabla Products debería ser ProductName.
¿ Pero, para que se usa este campo description ? Cooperator Modeler, da la posibilidad de agregar una propiedad descripción a cada tabla que tenga una Foreign Key a otra. Este tipo de campo, aparece como una propiedad que tiene el nombre de la tabla foránea mas el texto String. Por ejemplo, la entidad Order puede tener una propiedad llamada CustomerString, que contiene el nombre del cliente a la cual corresponde esa orden. ¿Pero como determina Cooperator Modeler, que en la propiedad CustomerString de la clase Order, debe devolver el campo CustomerName de la entidad Customer ? Pues, marcando dicha propiedad dentro del nodo Customers como: GenerateAsDescriptionField.
Esto es particularmente útil, cuando se quiere enlazar datos a una grilla, ya que tenemos en la misma entidad Order, el nombre del cliente propietario de la misma, sin tener que andar haciendo consultas extras para mostrar esa información.
Tenga en cuenta que esta propiedad no puede deshabilitarse, se deshabilitará automáticamente cuando seleccione otro campo como DescriptionField.

GenerateAsLazyLoad:
La traducción más correcta del patrón lazy load al español podría ser: carga a demanda. Antes que nada aclaramos que esta opción solo está disponible para propiedades que no sean columnas de la tabla, sino para agregaciones, es decir datos que vienen de otra(s) tablas.
Supongamos ahora que se necesitan todas las órdenes de un cliente, para eso tenemos un mapper de órdenes que tiene un método para ello y se lo invoca así:

Dim myOrders As OrderList = OrdersMapper.Instance().GetByCustomers(myCustomer)

Eso hace que se ejecute 1 store procedure que devuelve todas las ordenes de el cliente solicitado (digamos 10). Pero recordemos que la entidad Orders está compuesta además por los detalles de cada orden. Entonces el Mapper, por cada orden debe llamar también a otro stored procedure que devuelve los detalles de la misma. Esto es, la sentencia de arriba termina llamando a 11 stored procedures. (1 que devuelve 10 órdenes, y 10 que devuelven los detalles de cada orden) ¿No se ve muy eficiente verdad?
Es por esta razón, que el patron Lazy Load cobra una importancia fundamental aquí. Si dentro de la entidad Orders, se marca la propiedad OrderDetailsCollection como GenerateAsLazyLoad = True, hará que el comportamiento del Mapper (y de la entidad) cambie rotundamente.
Siguiendo con el mismo ejemplo, la misma instrucción, en vez de ejecutar 11 stored procedures se ejecutará solo 1, y se devuelve la colección de objetos pero sin detalles. Es decir los objetos vienen con la propiedad OrderDetailsCollection vacía, y se retarda la carga de la misma hasta cuando alguien la utilice. Este mecanismo de “carga a demanda”, permite optimizar el rendimiento de las aplicaciones de una forma radical. Además, lo interesante de este patrón, es que el programador no tiene que preocuparse si la clase tienes los valores cargados o no, el siempre debe pensar que si los tiene, es la clase misma la responsable de verificar si se trajeron los datos o no, y en este último caso obtenerlos efectivamente. Además hemos incorporado un mecanismo denominado Dependence Injection, que usa un archivo de configuración y que permite a la entidad decidir que mecanismo usar para cargar estos datos, ya que la entidad podria estar implementada en un sistema distribuido, y en vez de realizar una llamada a un Mapper que se conecta con una base de datos local, podría hacerlo por medio de un WebService o algún otro mecanismo.
Recordemos por otro lado, que si una entidad está marcada como ReadOnly, se mantiene en cache mientras viva la aplicación, y de este modo, si una entidad tiene una agregación de un tipo marcado como ReadOnly, tampoco se llama sucesivamente a un store procedure por cada objeto de la colección obtenida sino que se devuelve una copia de la cache mejorando exponencialmente la performance de los mappers.

GenerateAsReadOnly:
Permite definir una propiedad como solo lectura protegiendo asi la escritura de la misma.

GenerateAsType:
Esta opción se usa para definir de que tipo será una agregación dentro de una entidad. Y decimos dentro de una entidad, porque las clases del tipo Object no tienen Agregaciones, ya que son clases simples. Recordemos que por cada tabla siempre hay una clase del tipo Object, y que puede crearse a su vez todas las entidades que se quiera. Con esta opción, se decide si una agregación es del tipo Object o del tipo Entity
El problema que se puede platear cuando se adicionan muchas agregaciones en una entidad es el denominado acoplamiento. Pero, ¿Que es el acoplamiento? En pocas palabras, es cuando las clases comienzan a tener cada vez más y más referencias a otras clases llegando a un punto donde se hace imposible obtener solo una parte si no tiene acceso al todo. Por ejemplo, si se modelan las entidades para que desde un objeto Order se pueda acceder a su detalles y desde estos detalles a los productos y desde los productos a los proveedores, etc, escribiendo código mas o menos así…

Dim o As Order
o = OrderMappers.Instance().GetOne(144
Dim name As String
name =
o.OrderDetailsCollecion(2).ProductEntity.SuppliersEntity.SupplierName()

Estamos en problemas….

Ya que cuando se quiera obtener una simple orden se termina obteniendo una cantidad enorme de información que no se buscaba originalmente y que lamentablemente esta acoplada con la orden. El acoplamiento es intrínsecamente malo y quien lo ha sufrido puede dar pruebas de ello. ¿Y cómo se puede evitar? Pues acotando las entidades y una buena forma de hacerlo es hacer que las agregaciones de una entidad sean del tipo Object y no del tipo Entidad, ya que los Object no tienen otras agregaciones y de esta forma se cortan la cadena de acoplamiento. Esto no quiere decir que usted no pueda definir entidades como agregaciones de otras entidades, Modeler le da la posibilidad y la responsabilidad de modelar sus entidades como mas quiera.

GeneratePropert:
Especifica si se desea generar dicha propiedad como parte de la clase.

IsXxxxxxx:
Las demás opciones no pueden modificarse y se obtienen a partir de la ingeniería inversa que se hace sobre el modelo relacional. Estas opciones son usadas por los templates de generación de código para decidir como generar el mismo.
Por ejemplo, si se elije no agregar una determinada propiedad a una entidad pero dicha propiedad es parte de la PrimaryKey o de la ForeignKey de la tabla relacionada, no pueden dejar de agregarse ya que cuando se quiere persistir dicho objeto en las tablas, daría un problema de campo requerido o de integridad referencial. En esos casos la propiedad se genera pero como protected, es decir se ve solo dentro de la clase, y la entidad la almacena internamente, aunque desde fuera del ensamble de entidades no se puede acceder.
Así se van tomando decisiones para generar el código, en base a cada una de estas opciones que son autodocumentadas y por eso no las explicamos aquí una por una.


A %d blogueros les gusta esto: