7. Underthecovers Multi-TenancyShared DB AddsTenantId to “Multi-Tenant transactions” Updates subtype groups Assigns/Filters by Tenant in CRUD operations
18. Implementation IntensionalRelationships SQL Views SelectUserId, ProgramIdFromUser, Program Where NOT EXISTS (Select * fromNotAuthorizedWhereNUserId = UserId and NProgramId = ProgramId) Select‘email’ AS IECType UNION Select‘msn’ AS IECType UNION Select‘skype’ AS IECType UNION Select ECType as IECType From ECommunicationType Select‘Invoice’ AS DocumentType, InvoiceId as DocumentId from Invoice UNION Select‘Invoice’ AS DocumentType, PaymentId as DocumentId from Payment UNION Select‘Invoice’ AS DocumentType, PurchaseId as DocumentId from Purchase
Buenos días, mi nombre es Gustavo Proto, pertenezco al Equipo de Desarrollo de GeneXus.En esta presentación quisiera contarles sobre algunos escenarios que han captado nuestra atención y para los cuales estamos “procesando” una solución. El objetivo es hacerlos partícipes de npor la frecuencia en que se dan, el trabajo que generan en los que estamos trabajando. Estamos hablando de escenarios habituales en el desarrollo de aplicaciones cuya conceptualización podría con el objetivo de
Esta es una foto del equipo de desarrollo durante una reunión de “brainstorming”.Quizás ustedes no se hayan dado cuenta durante el evento pero esta gente que ustedes pueden ver deambular por los pasillos cabizbaja, con cara de preocupada (hasta que da su charla) también se ríe. Aquí está la prueba!Esta gente vibra y disfruta, de diferentes formas, lo que hace. Ojalá ustedes puedan disfrutar del mismo modo haciendo su trabajo utilizando el nuestro: GeneXus.Esta charla muestra algunos de los escenarios que en esa y otras reuniones hemos aislado, discutido y, en algunos casos seguimos discutiendo en nuestro Wiki interno que cuenta ya con 10000+ páginas con unas 46000 revisiones.Que se discute, no quedan dudas.Creemos que es importante para todos que ustedes conozcan nuestra forma de trabajo y que estén al tanto de los principales escenarios que queremos resolver. Estamos juntos en este barco.
Seguramente muchos de ustedes conozcan el significado de SaaS (Software as a Service). A los efectos de esta presentación, es la venta del uso de una aplicación a demanda. En este esquema, la aplicación “sirve” a sus usuarios (Tenants), normalmente desde servidores pertenecientes al propietario de la aplicación o a ISPs (Internet Service Provider).Los costos del servicio se ven afectados por diferentes variables: hardware, software, ancho de banda, etc. En general, cuanto más Tenantspodramos servir con el mismo “equipamiento”, menores serán los costos unitarios.Por otro lado, los requerimientos de los Tenants, a nivel de seguridad, disponibilidad, nivel de utilización, etc. deben ser considerados si queremos “llegar” a Tenants “de porte”.Los puntos anteriores afectan la arquitectura de las aplicaciones que se quieren vender en esta modalidad. En grandes líneas, tenemos tres categorías, en orden inverso de costo: Base de datos separadas Base de datos compartida y esquemas separados Base de datos compartidaCon GeneXus pueden implementarse cualquiera de las categorías mencionadas. Sin embargo, la opción de menor costo al usuario, que es soportar varios Tenants compartiendo la base de datos implica un alto nivel de cambio y/o mantenimiento de la aplicación.
Supongamos la aplicación de Invoicing, característica de la demostración de GeneXus como la vemos en el diagrama de transacciones. Transformar en multi-tenant esta aplicación, implica dos tipos de tareas. Por un lado el mantenimiento/seguridad/selección de tenants que, en última instancia, termina determinando el "Active Tenant". Por otro, una vez identificado el "Active Tenant", hacer que la aplicación lo considere en las operaciones que corresponda:Filtros por tenant en las consultas (procedimientos, web panels, queries, etc.)Actualizaciones a la base de datosCambiar definiciones de subtiposMantener todo lo anterior
La solución propuesta implica los siguientes pasos:Agregar la transacción de Tenant.-Identificar la transacción anterior como la "Tenanttransaction“. Identificar las transacciones Customer, Invoice y Product como "Multi-Tenanttransaction”Ver que, en este caso, la transacción Country NO se seleccionó como Multi-Tenanttransaction porque se entiende que los Countries son globales (los ingresados por un Tenant son visibles por los otros).-Por último, se define un Data Provider (que llamaremos TenantDP) que tenga como miembro al menos la llave primaria de la transacción identificada como "TenantTransaction".
En este escenario, se tiene una transacción de Person y dos subtipos de ella, Student e Instructor. El concepto es modelar que existen personas y que, adicionalmente, algunas pueden ser estudiantes y algunos instructores.Si bien esto es modelable en GeneXus, existen algunas cosas que nos gustaría mejorar para lo cual estamos trabajando en lo que llamamos “Ingreso del subtipo y supertipo juntos”.
Una transacción puede “Extender” a otra como forma de especialización. En este ejemplo decimos que Student extiende Person y esto nos da bastante potencia adicional. Por ejemplo:- La definición de subtipos es más “natural” para este caso ya que se define en la misma transacción que extiende No es necesario duplicar reglas o eventos. Pueden ser heredados automáticamente de la transacción extendida. El resultado final es más amigable para el usuario finalLa transacción que extiende puede tener más atributos que la extendida.
Adicionalmente, podríamos expresar la relación entre la transacción “padre” y la “hija” así como la de cada “hija” con sus hermanos. Entre la transacción “padre” y las “hijas” podríamos hablar de relación Total (todos los registros del padre tienen al menos un hijo) o Parcial (hay registros del padre sin hijos). Entre los hermanos podríamos hablar de relación Exclusiva (no puede tener hermanos) o Superpuesta (puede tener hermanos).Esto nos daría un conocimiento adicional que nos permitiría automáticamente controlar las operaciones CRUD sobre la transacción padre y sus hijas. Por ejemplo, teniendo una relación Total y Exclusiva, al eliminar un registro de la transacción hija se eliminaría automáticamente la del padre.
Supongamos que tenemos las transacciones User y Program, en una aplicación de autorización, y que todos los usuarios tienen acceso a todos los programas. Podemos decir que existe una relación de “está autorizado” entre User y Program. Podríamos definir dicha relación con una transacción Authorized como la que se indica.En GeneXus, sin embargo, la transacción Authorized almacena la relación entre usuarios y programas por “extensión”, es decir, sólo los registros existentes en dicha transacción representan a los usuarios y los programas a los que están autorizados.Esto es inconveniente en la medida que, siguiendo con que todos los usuarios están autorizados a todos los programas, tendríamos que insertar en la transacción Authorized las combinaciones posibles de User y Program, y mantenerla.
Una posible alternativa es indicar que la transacción Authorized es una transacción por intensión. Con esto, estaríamos indicando que las tuplas de la transacción se calculan, en este caso, a partir de otras transacciones.Una posible notación para definir la forma de calcular las tuplas de esta transacción es la mostrada que se lee como: “Include” las combinaciones posibles de UserId y ProgramId.Claro que un esquema de seguridad donde todos acceden a todo es un lio. Por ello, tenemos que introducir algunas restricciones.
Es evidente que una aplicación de seguridad donde todos tienen acceso a todo es, al menos, poco práctica. Agreguemos entonces la transacción NotAuthorized que indica qué usuarios NO están autorizados a qué programas.Esto nos llevaría a modificar la forma de calcular las tuplas de la transacción Authorized, de la siguiente forma.
Otroescenario en el quepodríamosutilizarlasrelacionesporintensiónes el queidentificamoscomo “Dominiosenumeradosextensibles en run-time”. En esteescenario, se tiene un dominio del cual, en diseño, conocemossolamenteuna parte de los valoresposibles. Este subgrupo de valoresesrelevante en la medida en que son utilizados en el código.Porejemplo, tenemos el dominio de los “Tipos de comunicaciónelectrónica”. No podemos saber de antemanoquétipos se inventarán en el futuro. Poresotenemosunatransacciónquepermitirámantenerlos. Sin embargo, sísabemosquenecesitamosuno, el email, porque la aplicación lo necesita (en algúnmomentomanda mails). Para esesubgrupo, definiríamos un dominioenumerado.Estonoslleva a que, durante la instalación, debamoscargar la transacción de “Tipos de comunicaciónelectrónica” con los valores del dominioenumerado y, obviamente, ponerreglasqueevitenqueseaneliminados/modificados.Una forma de mejorar la definiciónesevitar la carga y definir la transaccióon “Tipos de comunicaciónelectrónicaimplícita”, que se cargaríacomo se muestra.
Otro escenario interesante es el que ocurre, por ejemplo, con la contabilidad. Los movimientos contables suelen referenciar a los documentos que los originaron. Modelar esto considerando todas las posibilidades es complejo y normalmente se modela de la forma que se muestra.Este diseño tiene el inconveniente de recorrer los movimientos contables mostrando datos de los documentos que lo originan requiere un case (case DocumentType = “Invoice”, ForEach a Invoice, por ejemplo).
Se define un Data Selector y se identifica como un Data Selector Implícito (propiedad).
Aquí se muestra el caso en que se quiere utilizar un Data Selector cualquiera pero NO el implícito y también el que no se quiere utilizar ninguno.