Está en la página 1de 25

MANEJADORES DE BASE DE DATOS IBM Informix Dynamic Server (IDS) 9.

30 proporciona fiabilidad superior, atendiendo las necesidades de las exigentes prcticas actuales del ebusinessparticularmente para aplicativos que requieran transacciones de alto desempeo. Soporta requisitos de procesamiento de transaccin online, complejos y rigurosos. Optimiza capacidades de inteligencia del negocio competitivas Maximiza operaciones de datos para el grupo de trabajo y para la empresa en total. Proporciona la firmeza de una administracin de base de datos comprobada, mejor de su especie. Informix Dynamic Server con J/Foundation combina las caractersticas de IDS con un ambiente abierto, flexible, empotrado de Java! Virtual Machine. IDS con J/Foundation permite que los desarrolladores de base de datos escriban lgica de negocio del ladoservidor usando el lenguaje Java!. Java User Defined Routines (UDRs) tienen completo acceso a las caractersticas de la base de datos extensible lder mundial, de la base de datos IDS. Haciendo del IDS la plataforma ideal para el desarrollo de base de datos Java. Adems de Java UDRs, el IDS est en conformidad con el estndar SQLJ para procedimientos almacenados en Java, permitiendo el uso de los paquetes Java estndar que se encuentran incluidos en el Java Development Kit (JDK). Escribir UDRs en Java proporciona aplicativos mucho ms flexibles que se pueden desarrollar ms rpidamente que C, y ms potentes y administrables que los lenguajes de procedimientos almacenados. Una extensin adicional de escribir UDRs en Java es escribir mdulos DataBlade en Java. Los mdulos DataBlade son colecciones de nuevas funciones del ladoservidor y tipos de datos puestos en conjunto para extender el IBM Informix Dynamic Server con el servidor de datos J/Foundation. El DataBlade Developer's Kit (DBDK) ahora soporta Java y permite el desarrollo, diseminacin y depuracin de UDRs en Java. La tecnologa IBM Informix DataBlade es lder en la industria en extender el servidor para permitir tanto la administracin de contenido rich, cuanto la lgica de negocio. J/Foundation est provisto con IDS en muchas de las plataformas IDS 9.30 soportadas. Las plataformas soportadas incluyen Sun Solaris 32 bit, Microsoft Windows NT/2000, Linux, IBM AIX, SGI Irix, y Compaq Tru 64 IBM Informix Dynamic Server (IDS) 9.30 proporciona fiabilidad superior, atendiendo las necesidades de las exigentes prcticas actuales del ebusinessparticularmente para aplicativos que requieran transacciones de alto desempeo. Soporta requisitos de procesamiento de transaccin online, complejos y rigurosos. Optimiza capacidades de inteligencia del negocio competitivas Maximiza operaciones de datos para el grupo de trabajo y para la empresa en total. Proporciona la firmeza de una administracin de base de datos comprobada, mejor de su especie. Informix Dynamic Server con J/Foundation combina las caractersticas de IDS con un ambiente abierto, flexible, empotrado de Java! Virtual Machine. IDS con J/Foundation permite que los desarrolladores de base 1

de datos escriban lgica de negocio del ladoservidor usando el lenguaje Java!. Java User Defined Routines (UDRs) tienen completo acceso a las caractersticas de la base de datos extensible lder mundial, de la base de datos IDS. Haciendo del IDS la plataforma ideal para el desarrollo de base de datos Java. Adems de Java UDRs, el IDS est en conformidad con el estndar SQLJ para procedimientos almacenados en Java, permitiendo el uso de los paquetes Java estndar que se encuentran incluidos en el Java Development Kit (JDK). Escribir UDRs en Java proporciona aplicativos mucho ms flexibles que se pueden desarrollar ms rpidamente que C, y ms potentes y administrables que los lenguajes de procedimientos almacenados. Una extensin adicional de escribir UDRs en Java es escribir mdulos DataBlade en Java. Los mdulos DataBlade son colecciones de nuevas funciones del ladoservidor y tipos de datos puestos en conjunto para extender el IBM Informix Dynamic Server con el servidor de datos J/Foundation. El DataBlade Developer's Kit (DBDK) ahora soporta Java y permite el desarrollo, diseminacin y depuracin de UDRs en Java. La tecnologa IBM Informix DataBlade es lder en la industria en extender el servidor para permitir tanto la administracin de contenido rich, cuanto la lgica de negocio. J/Foundation est provisto con IDS en muchas de las plataformas IDS 9.30 soportadas. Las plataformas soportadas incluyen Sun Solaris 32 bit, Microsoft Windows NT/2000, Linux, IBM AIX, SGI Irix, y Compaq Tru 64 Nombre del Formato: Tipo de Formato: Descripcin del Formato: Formato disponible en Data Junction Enterprise: Formato disponible en Data Junction Profesional: Nombre del Editor: Ms informacin en: Comentarios adicionales: Funciones Oracle Requisitos previos: Usted necesita saber los valores de las variables de entorno siguientes: ORACLE_HOME sta es la trayectoria a su directorio de la instalacin del orculo. Se define generalmente en la escritura de la conexin de UNIX de su usuario del orculo y de todos los usuarios del cliente del orculo. ORACLE_SID ste es el nombre del caso de la base de datos que usted desea conectar con. Tambin se define en el ambiente de UNIX de su usuario del orculo y de todos los usuarios del cliente del orculo. Descubra los valores de estas variables por el loggin adentro como usuario que pueda conectar con la base de datos en la pregunta con sqlplus. Entonces mecanografe en su aviso de la cscara de Unix: prompt> echo $ORACLE_HOME /opt/oracle/oracle/8.0.3 prompt> echo $ORACLE_SID ORACLE 2 Informix Base de Datos Base de datos comercial S No (la versin Enterprise es necesaria si se desea leer o escribir datos en este formato) IBM Software Informix Sin comentarios

A simple PHP script using ora_* functions <?php putenv("ORACLE_SID=ORACLE"); putenv("ORACLE_HOME=/opt/oracle/oracle/8.0.3"); $conn = ora_login("scott", "tiger"); $curs = ora_open($conn); ora_commitoff($conn); $query = sprintf(&quotselect * from cat"); /* Long version */ /* ora_parse($curs, $query); ora_exec($curs); ora_fetch($curs); */ /* Short Version */ ora_do($conn, $query); $ncols = ora_numcols($curs); $nrows = ora_numrows($curs); printf("Result size is $ncols cols by $nrows rows. "); for ($i=0; $i<$ncols; $i++) { printf("col[%s] = %s type[%d] = %s ", $i, ora_columnname($curs, $i), $i, ora_columntype($curs, $i)); } for ($j=0; $j<$nrows; $j++) { for ($i=0; $i<$ncols; $i++) { $col = ora_getcolumn($curs, $i); printf(&quotval[%d, %d] = %s * ", $j, $i, ora_getcolumn($curs, $i); } printf(" "); } ?> Stevel at nettekllc dot com <?php

putenv( 3

"ORACLE_SID=sid1"); putenv( "ORACLE_HOME=/u01/app/oracle/product/8.0.5");

$handle = ora_plogon( "SCOTT@sid1", "TIGER")or die; $cursor = ora_open($handle); ora_commitoff($handle);

$query = "SELECT * FROM EMP"; ora_parse($cursor, $query) or die; ora_exec($cursor);

echo "<HTML><PRE>\n"; echo "$query\n\n"; $numcols = 0; while(ora_fetch($cursor)){ $numcols = ora_numcols($cursor); for($column=0; $column < $numcols; $column++){ $data = trim(ora_getcolumn($cursor, $column)); if($data =="") $data = "NULL"; echo"$data\t"; } echo "\n"; } $numrows = ora_numrows($cursor); echo "\nROWS RETURNED: $numrows\n";

echo "</PRE></HTML>\n";

ora_close($cursor);

?> Vistas y envolturas La implementacin de VFP de las vistas le permite trabajar con ellas de modo similar a como trabaja con tablas nativas. Como las tratar en detalle en este artculo, usarlas es clave para lograr ser independiente del software de soporte (backend). El otro concepto importante es el uso de envolturas. Por envoltura me refiero a la tcnica por la cual una funcin o comando, como SKIP, es "envuelta" en algn cdigo que la protege y almacenada en una funcin definida por el usuario, de forma tal que cada vez que se utilice, no tenga que codificar de nuevo la intercepcin de errores necesaria. Por ejemplo, la funcin SafeSkip puede verse como: Function SafeSkip LParameters cAlias llMoved = .F. * Avoid that "EOF encountered" error If !EOF(cAlias) Skip In (cAlias) If EOF(cAlias) * Moved to EOF, retreat Skip 1 In (cAlias) Else llMoved = .T. Endif Endif Return llMoved Mientras ms fuentes de datos intente accesar, ms cdigo condicional necesitar escribir. Escribir cdigo de esta forma le proporcionar los siguientes beneficios:

Crea un solo punto de mantenimiento si se necesita realizar algn cambio. El mismo cdigo puede accesar mltiples fuentes de datos. Puede comenzar a codificar aplicaciones cliente/servidor utilizando software de soporte en VFP hasta que se tome una decisin acerca de utilizar MS SQL Server, Oracle, Informix, Sybase o DB/2. Formularios de entrada de datos basadas en vistas. Cuando se trata de formularios de entrada de datos para una aplicacin cliente/servidor, puede utilizar ya sea SQL Passthrough (SPT), el cual es sencillamente pasar una cadena de SQL a travs de un ODBC a la fuente de datos, o vistas remotas, que significa enunciados SQL almacenados en DBC cuyas tablas temporales resultantes se comportan muy similar a las tablas nativas de VFP. El SPT almacenar su conjunto de resultados en un cursor local, as que Usted tendr que hacer un ciclo sobre los controles dentro de un formulario y aadir cada uno de ellos individualmente (por ejemplo, thisform.txtCustomer.Value = SQLResult.customer). Claro, actualizar el servidor requerira que Usted creara los enunciados SQL Update, Insert, y Delete apropiados, sin mencionar la verificacin de contencin multiusuario que debe ser codificada tambin, una tarea algo tediosa y plagada de oportunidades de error. Esta es la manera en que las cosas son usualmente hechas en Visual Basic (as que Usted sabe que debe de haber una mejor manera con VFP <risa>). Las vistas remotas, por otro lado, son increblemente sencillas de usar. Todo lo que necesita hacer es crear una vista con la misma estructura que la tabla subyacente, abrir la vista, (realizar el SQL Select), manipular la tabla temporal local que se crea de la misma forma en que lo hara con una tabla nativa de FoxPro, luego hacer un TableUpdate. El TableUpdate automticamente hace unos enunciados SQL Update, SQL Insert y SQL Delete por Usted y los pasa al administrador del controlador ODBC en tu estacin de trabajo. El administrador del controlador ODBC utiliza el controlador ODBC que Usted ha seleccionado para traducir el SQL en la sintaxis que el software de soporte (backend) entiende. Es as de sencillo. Yo recomiendo utilizar las vistas remotas para los ofrmularios de entrada de datos por las siguientes razones: Un conjunto de cdigo. El mismo conjunto de cdigo puede funcionar con tablas VFP o con tablas remotas en un SQL Server. Usted solo tiene que utilizar vistas locales o vistas remotas de acuerdo a las tablas que se utilicen. Desempeo. De muchas formas, las vistas pueden ser ms rpidas que el SPT debido a que TableUpdate (una funcin de VFP de bajo nivel) crea automticamente el cdigo SPT por Usted. El tiempo que tomara crear las cadenas de SQL update por Usted mismo y ejecutar el cdigo muy probablemente sera mayor que el TableUpdate. Si Usted piensa en cuanto es lo que en realidad TableUpdate realiza (registrar la memoria intermedia [buffer] de cambios, determinar el tipo de actualizacin hecha, leer las propiedades de la vista, construir el lote de enunciados SQL, pasarlos al administrador de manejador ODBC, regresar una bandera de xito/fracaso y limpiar la memoria intermedia de cambios), estoy seguro de que Usted estar de acuerdo con que puede tener mejor desempeo que el SPT. Todo lo anterior se puede hacer sin un solo error de sintaxis. Las propiedades de las vistas ofrecen una funcionalidad adicional sobre el SPT. Por ejemplo, para simular una cuenta de cinco BatchUpdate, se necesitara concatenar cinco enunciados SQL con punto y comas antes de pasarlos al ODBC. El SPT an tiene un muy importante lugar en la aplicacin cliente/servidor; Discutir ms acerca de esto en el Paso 3. Para mayor informacin sobre la utilizacin bsica de las vistas locales y remotas, refierase a la VFP Developer's Guide. Todas los comandos relacionados con datos deben de pasar a travs de una funcin. Casi la peor cosa que puede hacer para convertir en difcil el diseo de su aplicacin, es codificar directamente (hardcode) comandos de acceso, tales como los enunciados SQL, Zap, Pack, Reindex, Seek y 6

dems. En otras palabras, luce su cdigo como el siguiente? Function PurgeOrders * This function purges (deletes) orders shipped * prior to the date passed. LParameter dShipDate Local lcMsg Select Count(*) as OrderCnt from Orders ; Where ShipDate <= dShipDate Into Cursor tcPurge If _Tally = 0 lcMsg = "There are no orders to purge." Else Delete from Orders Where ShipDate <= dShipDate lcMsg = Trim(Str(_Tally)) + ; " orders were purged from the system." Endif MessageBox(lcMsg) EndFunc Esta clase de enunciados SQL es solo buena para accesar tablas que se pueden encontrar en su ruta de acceso. Dentro del mundo cliente/servidor puede comunicarse con las fuentes de datos por medio de un manejador de conexin (connection handle). Para las vistas, la clusula de conexin remota <ConnectionName | DataSourceName> del comando Create SQL View habilita que una vista accese datos remotos. Y para el SQL en lnea, la funcin de FoxPro SQLExec() es utilizada para pasar enunciados SQL al servidor por medio de ODBC. Regresa un 1 si hubo un error, 1 en caso de xito y un 0 si una peticin (query) asncrona est pendiente de completarse an. Como ejemplo, aqu est como obtener un cursor de rdenes de venta de un cliente dado utilizando SQL Passthrough: llSuccess = SQLExec(goEnv.nHandle, ; "Select * From ORDERS Where Customer = ?cCustomer",; "tcOrders") > 0 Si Usted hubiese empleado una funcin de envoltura para el enunciado SQL Select dentro de PurgeOrders, entonces podra condicionalmente ejecutarlo contra datos en el SQL Server, datos en el servidor de archivos o incluso datos en la estacin de trabajo local. Debe crear clases de las funciones necesarias para hacer el acceso 7

de datos independiente del software de soporte (backend). Aqu esta la funcin PurgeOrders reescrita de forma cliente/servidor: Function PurgeOrders * This function purges (deletes) orders shipped * prior to the date passed. LParameter dShipDate Local lcSQLStr lcSQLStr = "Select Count(*) as OrderCnt " + ; "from Orders " + ; "Where ShipDate <= ?dShipDate" This.SQLExecute(lcSQLStr, "tcPurge") If Reccount("tcPurge") = 0 lcMsg = "There are no orders to purge." Else lcSQLStr = "Delete from Orders ; Where ShipDate <= ?dShipDate" This.SQLExecute (lcSQLStr) lcMsg = Trim(Str(Reccount("tcPurge"))) ; + " orders were purged from the system." Endif MessageBox(lcMsg) EndFunc Function SQLExecute * Wrapper for VFP function SQLExec LParameters cExecuteStr, cCursor Local llSuccess cCursor = Iif(PCount() = 1, "SQLResult", cCursor) 8

llSuccess = .T. If goEnv.lRemote llSuccess = (SQLExec(goEnv.nHandle, ; cExecuteStr, cCursor) > 0) Else && local, just macro expand cExecuteStr * Add VFP "Into Cursor..." clause If Upper(Left(cExecuteStr,6)) = "SELECT" cExecuteStr = cExecuteStr + ; " Into Cursor " + cCursor + " NoFilter" Endif * This should be error trapped to return llSuccess &cExecuteStr Endif Return llSuccess EndFunc Notar el uso de Reccount() vs. _Tally. Los cursores SPT no actualizan _TALLY, as que tendr que olvidarse de utilizar esta variable tan agradable. Sin embargo, no tendr que preocuparse de que Reccount() contenga los registros eliminados, dado que las fuentes SQL de datos remotas no tienen una eliminacin de dos etapas. Y si el software de soporte fuese una base de datos de VFP, la clusula NoFilter prevendra que VFP creara un filtro en vez de una tabla temporal. La segunda peor cosa que puede hacer para convertir su aplicacin en un diseo cliente/servidor difcil es incluir funciones de VFP en sus SQL Selects. Sin embargo, si Usted tiene una envoltura como SQLExecute, tiene la oportunidad de leer el enunciado SQL antes de ejecutarlo y convertirlo a la sintaxis especfica del software de soporte. Por ejemplo, la funcin de SQL Server, Convert() se utiliza para convertir tipos de datos. As que, Usted probablemente podra imaginarse como se vera el cdigo para encontrar "Str(" o "Val(" en una cadena y hacer una StrTran() para poner la funcin Convert en lugar de las anteriores. Una ltima opcin es remover la funcin incluida y hacer el enunciado SQL independiente del software de soporte, luego utilizar la funcin VFP especfica en el cursor local. Utilice procedimientos almacenados o peticiones parametrizadas. En trminos de velocidad de ejecucin, no hay nada ms rpido que un procedimiento almacenado (stored procedure, SP). Dado que son precompilados y viven en el mismo edificio que las tablas, qu podra ser ms eficiente?. La forma en que los parmetros necesitan ser pasados al software de soporte es casi siempre diferente, as que, de nuevo, una funcin de envoltura se vuelve til aqu. Por ejemplo, tome nota de la sintaxis distinta entre VFP y el SQL Server: 9

SQLExec("usp_GetOrders('Acme')") && VFP SQLExec("usp_GetOrders 'Acme'") && SQL Server Todo lo que Usted necesita para resolver esto es mejorar la funcin de envoltura SQLExecute para manejar procedimientos almacenados. (Le dejar esta sencilla tarea a Usted). Si no desea irse por la ruta de los procedimientos almacenados, siempre estn las peticiones parametrizadas almacenadas en objetos de negocios. Con las peticiones parametrizadas, no tiene que preocuparse de la sintaxis de llamada de procedimientos almacenados especficos del software de soporte, ni tiene de preocuparse acerca de rescribir los procedimientos almacenados para cada fuente de datos. La disminucin de desempeo que se obtiene puede bien valer el incremento en la mantenibilidad. Usted ya ha visto como es que se ve una peticin parametrizada; es solo un enunciado SPT: llSuccess = SQLExec(goEnv.nHandle, ; "Select * From Orders Where Customer ; = ?cCustomer", "tcOrders") > 0 Note la sintaxis de la condicin de filtrado: Customer = ?cCustomer. La sintaxis es importante debido a que: 1) la mayora de los software de soporte la soportan; y 2) le evita tener que construir los parmetros del enunciado SQL en una cadena de caracteres especfica del software de soporte: Case lSQLServer "...Customer = '" + cCustomer + "' And ; shipdate <= '" + DTOS(dShipdate) + "'" Case VFP "...Customer = '" + cCustomer + "' And ; shipdate <= {" + DTOS(dShipdate) + "}" Otro beneficio es que no se topar con el "error del apstrofe", que ocurre cuando intenta construir un enunciado SQL como el anterior, pero la variable tiene un apstrofe en ella (por ejemplo, "Jim's"). Dado que su valor es evaluado antes de que la cadena sea enviada al servidor, terminar con comillas no apareadas correctamente y con un error de tiempo de ejecucin. Como puede ver, el uso de "?" puede realmente compactar su cdigo, as que yo recomiendo su utilizacin ampliamente. Por las anteriores razones, recomiendo SPT en vez de las vistas, siempre est creando una peticin ad hoc y/o no intenta actualizar la fuente de datos. Muchas personas crean vistas para propsitos de reporteo, pero en sistemas grandes, no puedo ver la razn de incurrir en la sobrecarga de utilizar vistas cuando un procedimiento almacenado o un enunciado SPT SELECT puede ser implementado en su lugar. (A menos que dese exponer una vista de lado del servidor a sus usuarios). El DBC de vistas del lado del cliente se puede volver demasiado sobrecargado con datos que no necesita mantener, dado que no hay propiedades de la vista que realmente necesiten ser establecidas. Encuentre maneras creativas de limitar los conjuntos de resultados. 10

Dentro del paradigma cliente/servidor, los conjuntos de registros son transferidos desde el servidor hacia la estacin de trabajo local, por tanto, deben ser lo ms pequeos posible para reducir el trfico en la red. Por lo tanto, de manera algo diferente a como funcionan las funciones de aplicaciones de servidor de archivos VFP, las formas se deben abrir sin datos. Esto adems ayudar a mantener una carga ligera causada por las formas, an y si la cantidad de sus datos crecen ms all de la capacidad de bases de datos de servidores de archivos, como VFP. Y si piensa al respecto, tiene sentido dar a los usuarios solo aquello que buscan. Por qu presentar al usuario una tabla que tiene 10,000 ordenes de venta abiertas cuando solo puede trabajar con un cliente a la vez? Piense que hemos programado as, durante tanto tiempo, debido a que las herramientas de bsqueda incremental nos dotaron de capacidades de navegacin rpida, an entre grandes cantidades de datos. Si bien es cierto que esto es aceptable en sistemas pequeos, la carga se volvera insoportable en una red y su aplicacin no escalara al mismo paso que los datos y los usuarios lo hicieran. Vistas parametrizadas. As que si su forma se abre sin datos en el mundo cliente/servidor, como le hacemos para obtener datos? Necesita proporcionarle a sus usuarios una herramienta para introducir criterios de filtrado. Estos valores servirn como parmetros de la porcin Where del enunciado SQL de la vista. Usted puede proveer esta funcionalidad de muchas formas diferentes, puede elegir entre muy sencillas hasta muy complejas. Una implementacin sencilla es tener una forma adherida a una vista parametrizada. Cuando un usuario entra en el modo Find, Usted puede proveer una caja de texto para introducir el valor del parmetro. Por ejemplo: * Create this view when you create the form. Create SQL View vOrders As Select * From Orders Where Customer = ?cCustomer * Open the view (with no data) in the Data Environment * or Load when you run the form. Use vOrders NoData * Get the customer parameter in Find Mode cCustomer = thisform.txtCustomer.Value Requery() && retrieve orders for cCustomer Una segunda tcnica que proporcionara mucha ms flexibilidad es proporcionar una herramienta QueryByForm (QBF). El QBF significa que en el modo Find, Usted puede proveer a los usuarios una manera para que introduzcan criterios de filtrado en cualquier (o solo la mayora) de los controles de una forma. Luego construya una cadena Where SQL de acuerdo y utilcela de una de dos maneras: 1. Construya un enunciado SPT para crear un conjunto de registros de los campos importantes y el ID nico. Construya una vista que est parametrizada por el ID nico. Los usuarios pueden navegar el cursor para encontrar los datos que necesitan y Usted hacer de nuevo la peticin de la vista basada en la ID nica. 2. Puede tambin utilizar la cadena SQL generada por la QBF para recrear la definicin de vista remota en tiempo real. Dado que su DBC de las vistas est en la estacin de trabajo, no hay problemas de contencin 11

aqu. (Ms de esto en el Paso 5) . Sugerencia: Existen al menos dos herramientas de otras compaas de software disponibles para implementar QueryByForm en VFP: QBF Builder Stonefield Query Manejando los enlaces entre controles y a tablas de bsqueda Este concepto de limitar el conjunto de resultados debera ser aplicado tambin a los controles. Qu de bueno tiene limitar las ordenes de venta a un cliente si se van a llenar varias casillas de seleccin (combo boxes) en la forma con datos de una tabla de bsqueda (look up)?. La lista de seleccin (list box) de varios miles de registros no tiene lugar en una aplicacin cliente/servidor. Hay al menos dos formas de evitar este problema. Una es no utilizar esta clase de controles en tablas grandes y en su lugar utilizar una caja de texto. Luego solo lanzar una forma separada con una tabla cuando el usuario seleccione una tecla de mtodo abreviado (hotkey) definida. Si Usted insiste en utilizar controles con registros mltiples, puede intentar con una segunda tcnica. No llene el control hasta que el evento GotFocus sea disparado. Esta tcnica de enlace tardo (late binding) le evitar la sobrecarga de llenar controles no utilizados. Puede utilizar una combinacin de cualquiera de estas tcnicas dependiendo del tamao anticipado de la tabla de bsqueda y solo controlarla con una propiedad y/o tabla de opciones. La VFP Developer's Guide le ofrece una sugerencia adicional: Hacer copias de las tablas de bsqueda frecuentemente utilizadas a cada estacin de trabajo. Como sea, el saber cuando mantener una versin local en sincrona con la versin del servidor me suena como una pesadilla. Por lo tanto, recomiendo una de las opciones anteriores. Formularios Uno a Muchos Los formularios uno a muchos deberan ser manejados como sigue. Cualquiera que sea la tcnica que Usted decida utilizar para formularios de tabla nica debe ser utilizada para la porcin del encabezado de un formulario uno a muchos. Las vistas de las tablas hijas, deben de ser parametrizada con el ID nico de la vista madre. As que cuando Usted navegue de un encabezado a otro, a la vista hija solo necesita ser pedida de nuevo. Al utilizar este mtodo, solo el hijo del encabezado actual necesita ser adquirido localmente. Mantenga las vistas en su propio DBC para tratar software de soporte independientemente. Si, en su diseo de marco de trabajo, las vistas son mantenidas en sus propios DBC, esto har la transicin a otro software de soporte ms sencilla. En otras palabras, cuando Usted desea que su aplicacin accese a fuentes de datos diferentes, desea mantener la mayor cantidad de piezas de su marco de trabajo intactas. Mantener las vistas en DBCs separados de las tablas (en un escenario donde VFP es el software de soporte) har el acceso las fuentes de datos remotas una cuestin de accionar un interruptor. La implementacin podra ser como sigue: Cree un directorio llamado \VFPViews, y almacene un DBC de vistas locales en l. Nombre el DBC como AppViews.DBC (\VFPViews\AppViews.DBC). Cree un directorio separado para cada fuente de datos que Usted desea accesar, manteniendo el mismo nombre del DBC de la vista. En otras palabras el DBC \SSViews\AppViews.DBC contendra vistas 12

que accesan un SQL Server. Dado que frecuentemente existen varios lugares en su cdigo donde se referir a las vistas de la base de datos, esto evitar que tenga que escribir cdigo condicional para cada software de soporte. En un archivo de inicializacin de su eleccin, almacene la informacin tal como el nombre DSN del ODBC, la ruta de directorios donde estn almacenadas las vistas, una bandera indicando si accesa datos locales o remotos y si son locales, la ruta de directorios de donde estn almacenadas las tablas de VFP. Establezca la ruta con Set Path To... al directorio de vistas apropiado al iniciar la aplicacin. Si es un software de soporte en VFP, establezca Set Path To al directorio de red donde se almacenan las tablas de VFP. Aunque es cierto que podra aadir el nombre de la base de datos de vistas al archivo de inicializacin, frecuentemente esto ya esta codificado por toda la aplicacin. El tener DBCs separados de las vistas tambin mantendr el tamao de stas manejable. Si el software de soporte fuese una base de datos de VFP, combinarlos significara que se necesitaran almacenar dos veces el doble del nmero de objetos de bases de datos. Si tal fuera el caso, Modify Database podra tomarnos un tiempo excesivamente largo en un sistema grande. Tambin notar que el DBC de la vista (sin importar si contiene vistas remotas o locales) es mantenido localmente, no en la red para ser compartido por todos los usuarios. Utilizar esta tcnica brindar mucha de la flexibilidad especfica de usuario, como aprender luego en este artculo. Todo este pedazo se siente como si se asumiera un almacenamiento local tambin, pero no est dicho explcitamente. Utilize Locate en vez de Seek para navegar en datos locales. Dado que todos los datos son accesados a travs de enunciados SQL en una aplicacin cliente/servidor, Usted pierde la habilidad de utilizar el mejor amigo de todo desarrollador de VFP, Seek. Enjuage esas lgrimas, porque hay una alternativa: Locate. Dado que los conjuntos locales de resultados sern (por definicin cliente/servidor) relativamente pequeos, el comando Locate ser ms que suficiente para mover el puntero de registro en un cursor local o una tabla temporal. Aqu vienen an mejores noticias. El conjunto de resultados de una vista es de hecho una tabla temporal. Para ver a que me refiero. Abra cualquier vista y verifique el valor que regresa DBF(). Debe de ver algo como C:\WINDOWS\TEMP\76633985.TMP. As que esta "cosa" de hecho tiene una presencia en el disco. Y en VFP, tiene una presencia en el disco que podemos indexar. As que, sintase libre de indexar al cursor de la vista tanto como desee si siente la necesidad de la velocidad. Pero de todas formas, yo me quedar con Locate en vez de Seek. Dado que Locate es, adems, optimizable con Rushmore, el utilizarlo con o sin ndice no har que falle, uno solo ser marginalmente ms rpido que el otro. Conclusin. Bueno, solo estamos a la mitad, pero desde ahora estoy seguro de que puede ver la luz al fondo del tnel. Las envolturas (wrappers) y las vistas son ciertamente las claves para hacer su cdigo independiente del software de soporte. Mantener estos conceptos en mente en todo momento le ayudar a hacer aplicaciones cliente/servidor flexibles y escalables. El siguiente mes, cubrir seis pasos ms y cerrar con un formulario de ejemplo que puede accesar una base de datos VFP tan bien como una base de datos SQL Server. Luego, Usted seguir por su cuenta. Nos vemos el mes siguiente, y hasta entonces, comience a envolver. Use claves primarias sustitutas para todos las tablas. Incluso antes de que VFP 3.0 nos diera la capacidad de agregar claves primarias a nuestros claves, el uso de un solo campo, o grupo de campos, para identificar de manera nica una fila de la tabla ha sido sugerida por 13

muchos como una prctica sana. En aplicaciones con servidor de archivos, no obstante, en muchas situaciones en realidad no haba necesidad de hacer esto; era solamente una buena idea. Sin embargo, con vistas, las reglas cambian. Para utilizar vistas (views) actualizables, debe existir un clave primaria en la tabla en la cual se basa la vista (generalmente no actualizo los datos de una vista multitabla). La razn es que debido a que la vista crea un resultado local establecido cuando se abre (USE <NombreVista>), usted necesita algn mecanismo para poder encontrar el registro subyacente en el servidor que est tratando de actualizar. Esto no siempre era necesario en un modelo de servidor de archivos, donde un registro compartido puede ser directamente editado. Para que las actualizaciones funcionen, las vistas requieren que usted establezca la propiedad KeyField en tiempo de diseo en el Diseador de Vistas (View Designer) o con DBSETPROP("Viewname.KeyField1", "Field", "KeyField", .T.) o establezca la propiedad KeyFieldList en el cursor abierto en tiempo de ejecucin usando CURSORSETPROP("KeyFieldList", <lista delimitada por comas de los campos de la clave primaria>). En cualquier, la vista utilizar los campos de clave (key fields) para encontrar el registro en el servidor en el que usted ha ejecutado SQL Update o SQL Delete. Las claves tambin sern utilizadas para detectar los conflictos de la actualizacin, reportar un error si alguien ha borrado el registro que usted est intentando actualizar o ha cambiado el clave. Aparte de ser una necesidad para las vistas actualizables, agregar claves primarias a sus tablas tambin hace que solicitar un registro en particular sea ms simple. Usted descubrir que en el mundo cliente/servidor necesitar a menudo esa capacidad. El argumento para los claves sustitutas. Si usted tiene campos mltiples que conforman sus claves primarias, sugiero utilizar adems una clave substituta generada por el sistema. Al tener este campo, tpicamente de tipo entero, le dar el lujo de una identificacin nica de la fila que le dar gusto tener. Adems, para las tablas hijas Usted querr agregar una campo entero adicional como clave externa (foreign). Usted lo llenara con la clave primaria sustituta del padre (parent) antes de grabar al hijo (child). Las ventajas de las claves sustitutas incluyen uniones (joins) ms rpidas, actualizaciones ms rpidas, eliminaciones ms rpidas y la recuperacin simplificada de los hijos de un padre. La nica desventaja est en generarlas. Yo utilizo una tabla de sistema de nmeros consecutivos, contiene una fila por la tabla en la aplicacin, pero esto puede causar problemas de conflicto multiusuario si no tiene cuidado. Debido a que estas claves realmente no tienen significado (por eso tambin se llaman claves abstractas), usted no debe tratar de obtener el siguiente nmero secuencial del servidor mientras que est a mitad de una transaccin. Esto puede crear demasiado conflicto en la tabla del sistema cuando usted necesita las claves primarias para una tabla muy activa. Es mejor conseguir la clave exterior de la transaccin y arriesgarse a perderla si una actualizacin falla. Otra idea puede ser utilizar una de las tcnicas para generar una identificacin nica localmente, eliminando el viaje al servidor y cualquier conflicto multiusuario posible. Igual como cuando nunca he dejado que se vaya ningn contratista de mi casa sin haberme recomendado a un buen reparador de techos, nunca dejo que una conversacin con un desarrollador termine sin preguntar por su tcnica para la generacin de identificaciones nicas. Dos interesantes que he escuchado que usan la generacin del lado del cliente son: 1. Utilice un GUID. Son de 26 caracteres de largo, (supuestamente) nicas en todo el mundo y rpidas para generarse. No son hermosas, pero valen la pena. 2. Consiga una identificacin nica de una tabla del sistema del lado del servidor al iniciar la aplicacin y despus utilice una propiedad local de la aplicacin como un contador. Concatene los dos para generar una cadena alfanumrica nica. Aunque estoy simplificando un poco, creo que esta 14

tcnica es utilizada en Code Book. Agregue una columna de tiempo a cada tabla. Las aplicaciones cliente servidor utilizan casi exclusivamente un bloqueo optimista (optimistic locking). Debido a eso, la verificacin de conflictos multiusuario se convierte en ms que un desafo de implementar. Debe recordarse continuamente mientras codifica: "quizs no tengo la ltima versin de estos registros". Aunque la clave primaria se utiliza para detectar conflictos de actualizacin, su capacidad se limita a detectar si otro usuario ha suprimido el registro que usted est intentando actualizar o si ha cambiado la clave. La clave primaria no le ayudar a determinar si otro usuario a hecho los cambios a los campos que no son parte de la clave antes de hacer efectivos sus cambios. Tpicamente, las aplicaciones cliente/servidor utilizan una cierta forma de columna con una marca de tiempo (timestamp), una que se modifica como parte de cada actualizacin, para indicar la ltima versin de un registro. (Digo "una cierta forma de marca de tiempo" porque el tipo de dato puede ser casi cualquier cosa). Esta columna entonces es revisada en el servidor durante cada actualizacin para determinar si est en conflicto con la versin local de la estacin de trabajo. Por ejemplo, una vista de VFP pudo generar el siguiente estatuto SQL despus de actualizar la vista del cliente: Replace state With 'NY' For city = 'New York' In vcustomers TableUpdate(.T., .F., "vcustomers"): * This is what is autogenerated by the view * and passed to the server. * There would be one of these per updated record. Update customers Set state = 'NY' ; Where cust_pkey = ?vcustomers.cust_pkey and ; timestamp = ?vcustomers.timestamp Si este estatuto de actualizacin SQL falla con un error de conflicto de actualizacin (Update Conflict), usted puede reportar a su usuario que alguien modific este registro mientras lo editaba. Lo que haga despus depende de que tan amable sea. En ltima instancia, o debe hacer una solicitud (query) de nuevo o puede intentar enviar un TableUpdate otra vez con el parmetro Force activado (que no se recomienda a menos que proporcione al usuario una comparacin campo por campo de los cambios). La propiedad de la vista, WhereType, es responsable de la verificacin de conflictos multiusuarios. Usted tiene cuatro opciones para determinar qu campos son comparados cuando se genera la porcin de la verificacin de conflictos del estatuto SQL. Key and Modified Fields (clave y campos modificados) y Key and Updatable Fields (clave y campos actualizables) suenan como funciones poderosas, pero siento que en la mayora de los casos estas opciones son demasiado peligrosas como para implementarse. (No me gustara que el usuario 1 y el usuario 2 actualizaran dos columnas diferentes del mismo registro sin que cada uno conociera primero los cambios del otro). Esto nos deja Key Fields Only (campos de clave) y Key and Timestamp (clave y marca de tiempo). Key and Timestamp solamente es soportada si su base de datos soporta una columna de tipo marca de tiempo 15

(timestamp). Esta columna es modificada automticamente por el servidor en cada actualizacin. La aplicacin cliente no mantiene este campo, la vista solamente incluir la columna en la verificacin de conflictos. El SQL Server tiene soporte para una columna de marca de tiempo. De hecho, el asistente SQL Server Upsizing Wizard tiene una opcin para crear una columna de marca de tiempo para cada tabla. La columna no es realmente de tipo de dato datetime, sino ms bien una cadena nica generada por el sistema. La belleza de ella es que el servidor la maneja automticamente y que es mucho ms exacta que el tipo de dato datetime (nunca tendr que preocuparse por dos usuarios actualizando a la misma hora exacta). Algunos comportamientos de los que hay que estar enterados al usar la columna de marca de tiempo del SQL Server: Si usted vuelve a hacer la peticin (query) despus grabar, la columna de marca de tiempo en el cursor de su vista local estar actualizada con el valor actual en el servidor. As, los intentos subsecuentes de grabar el mismo registro fallarn con un error de conflicto de actualizacin (Update Conflict) cuando se comparen las dos marcas de tiempo. Soluciones para las limitaciones del asistente Upsizing Wizard: El asistente de SQL Server Upsizing Wizard tiene muchos problemas que lo hacen, en mi opinin, casi inutilizable. La mayora de la gente que conozco ha tenido que escribir sus propias herramientas para resolver las limitaciones. Una virtud que lo salva es que el cdigo fuente de todos los asistentes y generadores ahora viene con la versin 6.0 de VFP. No es realmente tan difcil modificar el cdigo para superar sus limitaciones. El cdigo fuente est situado en \<localizacin de VFP 6.0>\Tools\Xsource\Xsource.zip. As que la clave y la marca de tiempo suenan excelentes para el SQL Server, pero qu hay sobre los otros sistemas de soporte (backends) que no soportan una columna de marca de tiempo? Y cmo puede mi prototipo con vistas locales de una base de datos de VFP funcionar con el mismo conjunto del cdigo? Mi solucin es agregar mi propia columna de marca de tiempo y mantenerla del lado desde el cliente o desde un disparador de actualizacin del lado del servidor. Entonces convierte el campo en un KeyField (campo de clave) (vase el paso 7) y utiliza Key Fields Only WhereType. As que su KeyFieldList podra ser cust_pkey y timestamp. (Note que los campos en la propiedad de KeyField o KeyFieldList de una vista no tienen que ser claves primarias o candidatas). Usted puede utilizar una columna de tipo datetime para este propsito. Sin embargo, la columna datetime de VFP tiene precisin de un segundo solamente, as que es posible que dos usuarios puedan actualizar el mismo registro dentro del mismo segundo. Si usted siente que esto es un problema potencial para su aplicacin, utilice otra tcnica para generar un nmero o cadena nica. Yo utilizaba esta solucin hasta que empec a usar SQL Server e inclu su columna de marca de tiempo. (Dado que usted no tiene ningn control sobre este nombre de campo, puede llamar su columna de marca de tiempo en VFP algo diferente para que no haya conflicto cuando cambie a SQL Server). Entonces puede simplemente cambiar el WhereType a Key and Timestamp (clave y marca de tiempo) y ya est listo. Vida sin fechas. Era un poco inquietante, bueno, quiz era ms como una sacudida repentina, descubrir que el SQL Server, como la mayora de las bases de datos del grandes, no soporta un tipo de dato para fechas (date). Debe utilizar un campo de tipo datetime. Si usted est convirtiendo una aplicacin existente de VFP, que utiliza campos de fecha (date), los problemas podran ser muy extensos. Realmente depende de cmo utiliza las fechas su aplicacin y de cunto le importa ver 12:00:00 al final de sus campos de la fecha. He resumido los problemas a los que me he enfrentado as como sus posibles soluciones. 16

Los controles limitan hasta los campos de la fecha. En los casos donde es simplemente inapropiado mostrar la porcin de la hora de un campo del datetime, obviamente usted tiene que realizar alguna clase de truco para perder la hora predeterminada de 12:00:00 AM. Tiene varias opciones. Usted podra utilizar DBSetProp para cambiar el datatype de la definicin de la vista de datetime a date. (Como se mencionaba en la parte 1, teniendo un DBC local de vistas elimina cualquier problema de conflicto multiusuarios). Create SQL View vOrder Remote Connection ; Remote1 As Select * from orders DBSetProp("vOrders.orderdate", ; "Field", "DataType", "D(8)") Use vOrders Hacerlo as truncar no slo la porcin del tiempo, sino que tambin le proporciona un campo de tipo fecha (date) de VFP en su vista, permitiendo a su cdigo especfico de fechas funcionar sin cambiarlo. Y afortunadamente, cuando usted ejecuta una TableUpdate en una vista con un campo del tipo fecha en l, se le anexa una hora predeterminada de 12:00:00:00 AM automticamente en el SQL Server... sin error. Si usted tiene controles que no estn enlazados a una vista sino a un cursor de solo lectura SQL Passthrough (SPT), puede utilizar la funcin de conversin de tipos de datos del software de soporte (backend) para hacer el truncamiento. Aqu est un estatuto SQL que se podra pasarse al SQL Server que hara exactamente eso: SELECT orderid, ; customerid, ; CONVERT(char(10), orderdate, 101) as orderdate ; from orders Observe que 101 refiere al argumento opcional de estilo de la funcin del CONVERT. 1 indica formato americano, mm/dd/yy. Luego le suma 100 si desea el siglo incluido. Para hacer que la funcin CONVERT funcione para datos locales tambin, usted puede crear un procedimiento almacenado (stored procedure) llamado "Convert" en la base de datos de vistas. Haga que acepte los tres argumentos de la funcin de CONVERT del SQL Server y, si se le pasa un datetime, que regrese SubStr(TToC(pDateTimeField), 1, 10). Usted tambin necesitar escribir un procedimiento almacenado Char para manejar el tipo de dato de la funcin del SQL Server, char(10). Los campos datetime no pueden estar "vacos". Como si perder los campos de fecha no fuera ya bastante malo, usted tambin debe enfrentarse con el hecho de que los campos datetime no pueden estar vacos en la mayora de las bases de datos. (Hay un mundo completo de funcionalidad limitada ms all de FoxPro, verdad?) Las columnas datetime deben ser llenadas por una fecha y hora vlidas o ser nulas (Null). Si usted permite que sus campos datetime acepten Null, solucionar rpidamente el problema de la interfase de usuario pero probablemente generar otros. Podra experimentar resultados inesperados al introducir ciegamente Nulls. (Por ejemplo, la comparacin de dos fechas donde una es nula devuelve Null, Empty (FechaNula) devuelve .F., etctera). Pero si usted est preparado para enfrentar estos problemas, Null realmente es prctico al presentar datos a los usuarios gracias al comando de ambiente Set NullDisplay to de VFP y a la propiedad NullDisplay de los controles como la caja de texto (text box). 17

Si usted no desea utilizar Nulls, VFP y el SQL Server son en realidad buenos con usted. El enviar una fecha vaca al servidor del SQL no causa ningn error. Sin embargo, el SQL Server crear un datetime predeterminado de 01/01/1900 12:00:000 AM. Ahora, cuando usted solicita esos datos, usted ver 01/01/1900 en el cursor local, suponiendo que usted ha utilizado alguna de las tcnicas discutidas anteriormente para truncar la hora. No creo que sea algo tan horrible como para que un usuario no deba verlo, pero si usted ha elegido establecer Set Century Off, 01/01/00 parecer como el 1 de enero del 2000. (Como si los problemas con el ao 2000 no fueran suficientes, al cambiar a SQL Server se crearn problemas del ao 1900!) He creado tres posibles soluciones. La primera es agregar un valor predeterminado a todos los campos datetime, uno que ponga en claro que esta es una fecha falsa, como 01/01/9999. (Observe que el tipo de dato datetime tiene un rango de fecha del 1 de enero de 1753 al 31 de diciembre del 9999). Una vez ms usted necesitara establecer Set Century On para distinguirlo del 1999. Una opcin similar es agregar un valor predeterminado de la columna a todos los campos datetime que sigan alguna regla de negocios. Por ejemplo, todas las fechas de envo (Ship Date) pueden estar predeterminadamente a ocho semanas despus de la fecha de la orden (Order Date), que es un campo requerido. La tercera opcin implica ms malabarismos. No sera fantstico si hubiera alguna manera de borrar cada fecha igual a {01/01/1900} en el cursor de la vista abierta, no enviar ninguna actualizacin al servidor y no dejar ningn cambio pendiente? Bien, puede hacerse y es algo como esto: Procedure OpenView LParameters pcView * Retrieve data form server Use (pcView) in 0 * Prevent update statements from going to server CursorSetProp('SendUpdates', .F., pcView) * Strip 01/01/1900 out of this cursor RemoveDefaultDates(pcView) * Remove pending changes/clear the change buffer TableUpdate(.T., .T., pcView) * Restore update capability to view CursorSetProp('SendUpdates', .T., pcView) Por brevedad, no proporcionar el cdigo para la funcin RemoveDefaultDates. Pero todo lo que lo hace es un ciclo por todas las columnas con campos del tipo fecha (date) y los substituye por {} si son iguales a {01/01/1900}. Ahora todas las pantallas de entrada de datos se vern y funcionarn como lo hacan cuando el software de soporte (backend) era solo VFP. Bien, esto funciona para las vistas, pero qu hay sobre los cursores del SPT? Solo necesita ejecutar la funcin RemoveDefaultDates sobre cualquier cursor que ser presentado eventualmente al usuario.

18

Diferencias entre los cursores SPT remotos y cursores SPT locales: Los cursores del SQL Passthrough son de solo lectura cuando estn creados de fuentes de datos de un servidor de archivos, pero de son de lectura/escritura cuando estn creados de una fuente de datos cliente/servidor. As pues, si usted est haciendo prototipos localmente, por supuesto necesitar cambiar el cursor a lectura/escritura antes de modificarlo. Matemticas de fecha. Usted necesita estar atento de cualquier matemtica de fechas que pudiera tener en su aplicacin. Dado que tiene campos datetime en el servidor (y puede tenerlos en un cursor local tambin) donde tena originalmente campos date, pueden ocurrir errores en los clculos. Por ejemplo:

?Date() + 20 && 03/08/99 + 20 = 03/28/99 ?Datetime() + 20 && 03/08/99 10:35:15 PM + 20 = ; && 03/08/99 10:35:35 PM! * against SQL Server: * ExpectedDate is 14 DAYS after order date Select orderdate, ; Orderdate + 14 as ExpectedDate ; From Orders * against VFP: * ExpectedDate is 14 SECONDS after order date Select orderdate, ; Orderdate + 14 as ExpectedDate ; From Orders Puede ver que el agregar un nmero a un campo datetime puede tener resultados diferentes basados en el software de soporte (backend). Es difcil decir si se agregarn segundos o das. Una solucin podra ser convertir el nmero incremental en una funcin. De ese modo, Usted tiene lo necesario para determinar cual es el software de soporte y proporcionar los clculos apropiados. Evitar esa sensacin de Empty() con los Nulls. Si usted es como yo, quizs usted ha aprovechado la flexibilidad que proporciona la funcin Empty() de VFP. Empty(eExpression) funciona para cualquier tipo de datos, excepto los objetos. Puede detectar cero, una cadena vaca, una fecha vaca o falso lgico con esta una funcin sin ni siquiera verificar el tipo de dato. Mala movida. 19

Los problemas pueden ocurrir porque despus de cambiar a SQL Server, puede ser que encuentre algunos valores inesperados de funciones y de solicitudes (queries). Puede ser que incluso estn en un tipo de datos diferente al que usted esperaba. Cuando estos valores se evalan con Empty(), o cualquier funcin en este caso, podra causar problemas importantes. Por ejemplo: ?Empty({}) && true ?Empty({01/01/1900}) && false ?Empty(Null) && false Usted ha visto el problema con {01/01/1900} en el paso 9, la vida sin fechas, as que sabe lo que puede ocurrir. Borrarlos localmente parecen ser la solucin ms fcil. Pero qu hay sobre el problema de Null? La mayora sabe que nulo no es vaco, pero saba que incluso si usted no tiene ninguna columna en su base de datos que acepte Null, puede ser obtenga valores Null del servidor? Intente esto en el SQL Server: Function GetMaxOrderQty lcSQL = "SELECT MAX(Quantity) AS nMaxQty" +; " FROM [Order Details] " +; " WHERE ProductID = 99 " SQLExec(lcSQL, "cBigOrder") If Reccount("cBigOrder") > 0 lnRetval = 0 Else lnRetval = cBigOrder.nMaxQty Endif Return lnRetval Cul es el tipo de dato del valor de retorno? Depende. Si se encontraron registros para ProductdID = 99, la respuesta es numrica. Si no hay registros encontrados para ProductdID = 99, la respuesta es Null, a pesar de que la columna de cantidad (Quantity) no soporta valores Null. La razn es que en solicitudes SPT para el SQL Server, usted no obtendr un cursor resultante sin registros para solicitudes de agregacin como esta. Usted obtendr un registro sin importar si se encontraron coincidencias, a menos que usted tenga una clusula Group By una columna que no sea de agregacin. Y en las columnas de agregacin tendrn un valor Null. Eso podra causarle problemas en muchos lugares si no tiene cuidado de evitarlo. En el ejemplo precedente, lnRetval sera nulo porque no hay ningn ProductID = 99. Para evitar obtener valores nulos, usted tiene varias opciones. Por supuesto, encontrar todas las funciones de agregacin en su cdigo y hacer un IsNull() el chequeo es una manera. Podra tambin escribir una envoltura (wrapper) para Empty, quizs IsEmpty, que detecte Null y 01/01/1900 tambin. Esto se puede utilizar para verificar los 20

valores de diversos tipos de datos sin temor de encontrar resultados inesperados. fialmente, agregando la funcin Count(), como en Count(*) as Cnt, a todas las solicitudes como stas, le da una manera comn de verificar si hay un valor retorno. La columna Cnt ser siempre numrica, as que ahora puede verificar si Cnt > 0 en vez de Reccount() > 0 sin temor a los Null. El caso para los controles no enlazados. Ya ha visto muchos problemas al trabajo con los campos que son de diferentes tipos de datos, dependiendo del software de soporte (backend). Yo los veo tambin. Estos problemas hacen que sea muy difcil de escribir un conjunto del cdigo para accesar mltiples fuentes de datos. Obviamente, no todas las aplicaciones requieren tal flexibilidad, pero para los que necesiten o quieran esta funcionalidad, los controles no enlazados (unbound) pueden ser la respuesta. Los controles no enlazados en un formulario no tienen tipo de dato. Usted toma el resultado de una solicitud y esencialmente "pinta" los controles con los valores del contenido del campo. Eso le dara lo necesario para manipular los datos de cualquier manera que necesite antes de presentarlos al usuario. Esto proporciona gran flexibilidad, pero tambin una tonelada de codificacin. Puede usted imaginarse cunto cdigo tomara para leer los datos, pasar por todos los controles, para pintar la forma y luego pasar de nuevo por los controles para crear el cdigo SQL que escribir las actualizaciones al servidor? Eso sin mencionar el tener que agregar el cdigo de validacin de tipo de dato a nivel de cada campo que obtiene cuando usa controles enlazados (bound). El desarrollador promedio de FoxPro esta tan acostumbrado a usar los controles enlazados que preferira masticar vidrio antes que escribir todo ese tedioso cdigo. Debe haber una manera mejor. Si tuviera que vivir mi vida otra vez, cambiara solamente una cosa: Habra creado otra capa de abstraccin de datos. (Bueno, dos cosas: tambin habra comprado acciones de Microsoft hace 10 aos. Quin saba?) La capa adicional sera implementada en la forma de un cursor de lectura/escritura con la misma estructura y contenido del resultado de la vista. Los controles se pueden estar todava enlazados a una fuente de datos, mientras que al mismo tiempo usted tiene la capacidad de manipular el cursor de cualquier manera antes de presentarlo. El proceso sera algo como esto: Procedure Load * For this test, open the form with data. Use vOrders In 0 * Get a copy of the result set. Select * from vOrders Into Cursor cOrders1 NoFilter * Make a readwrite copy of cOrders1. Use (DBF()) In 0 Again Alias cOrders * Close the temporary readonly cursor. Use In cOrders1 21

* * Now the Init of the controls fire, * which are each bound to cOrders. * cOrders will be the form's master alias. EndProc Ahora solo edite el formulario como de costumbre. En Save, vace el cursor editado nuevamente dentro de la vista y ejecute una TableUpdate en ella. Todo el marco de trabajo basado en vistas discutido anteriormente sera aplicable, simplemente est usando una capa adicional ms. Y con conjuntos de resultado pequeos, un requisito cliente/servidor, junto con el veloz motor de datos de VFP, el desempeo no debe ser un problema. Al darse usted mismo esta oportunidad de manipular los datos antes de presentarlos, obtiene lo mejor de los controles enlazados y no enlazados. Esto har posible la adicin de nuevas funciones donde los datos subyacentes no coinciden con lo que ve el usuario, por ejemplo, de diferentes monedas, multilinge y las representaciones carcter de datos como 4 DOZ (4 dozen, cuatro docenas). Creando un formulario que tenga acceso a mltiples software de soporte He proporcionado un formulario que es indicativo de cmo Usted puede disear un formulario que necesite tener acceso a fuentes de datos mltiples. Es tosco y sucio, con todo el cdigo de nivel de instancia, para facilitar el aprendizaje, pero siempre podr mejorarlo una vez que comprenda el diseo. Tambin por simplicidad, he creado solamente un campo de filtro y no he implementado Query by Form. Antes de que usted pueda ejecutar la forma, haga lo siguiente: extraiga los archivos y las carpetas, que estn en el archivo o cdigo, en cualquier directorio. Usted encontrar el formulario Orders, los grficos BMP para completar el formulario y main.prg. El subdirectorio AppData contiene una copia de la base de datos Northwind Traders en formato de VFP. (Utilic el asistente de transformacin de datos del SQL Server para hacer esto). El directorio SSViews contiene una vista remota, vOrders, en un DBC llamado AppViews. De manera similar, el directorio VFPViews contiene una vista local, vOrders, en un DBC llamado AppViews. (Revise el paso 5 en la primera parte del artculo para ms informacin sobre la estructura de archivos y directorios). Ejecute la versin 6.0 de VFP y fije el valor por defecto al directorio donde extrajo los archivos. Tenga el SQL Server 7.0 instalado y ejecutndose. En el panel de control, cree un DSN ODBC de usuario que conecte con la base de datos Northwind Traders y llmelo NORTHWIND_SS7. Para ejecutar el formulario contra el SQL Server, ejecute: MAIN("NORTHWIND_SS7"). Para ejecutar el formulario contra VFP como software de soporte, ejecute: MAIN("NORTHWIND_VFP"). Como usted puede ver en la figura 1, la barra del ttulo indica la fuente de datos. Elija la Find (encontrar), introduzca un cliente como "VINET" y despus elija Retrieve (extraer). Los cinco pedidos para este cliente sern extrados del servidor.

Formulario de ejemplo. No se emocione mucho buscando cdigo mgino, porque realmente no hay ninguno. De hecho, no slo es simple, sino casi idntico al cdigo que usted vera en un formulario enlazado a tablas intermedias.

22

Las nicas diferencias son la adicin de la clusula NoData del comando del USE en Load, la configuracin de la variable privada cCustomer que sirve como el parmetro de la vista y la llamada subsiguiente de la funcin de Requery que extraer los datos para el cliente apropiado. stos son los nicos dos procedimientos que pudieran generar algn inters remoto: PROCEDURE Load * Important for local views Set Exclusive Off * Need this for table buffering Set MultiLocks On Set Data To AppViews * No data on load, please Use vOrders NoData * Set optimistic table buffering CursorSetProp("Buffering", 5) ENDPROC PROCEDURE cmdfind.Click PRIVATE cCustomerID cCustomerID = "" IF Thisform.PendingChanges() WITH Thisform .Lockscreen = .T. IF Not Thisform.lFindMode thisform.lFindMode = .T. * Change to find mode this.Caption = "\<Retrieve" .SetAll("Enabled", .F., "textbox") .SetAll("Enabled", .F., "_commandbutton")

23

.txtCustomerID.Enabled = .T. .txtCustomerID.Setfocus() ELSE && In find mode, so Retrieve .SetAll("Enabled", .T., "textbox") .SetAll("Enabled", .T., "_commandbutton") this.Caption = "\<Find" .txtCustomerID.Enabled = .F. cCustomerID = .txtCustomerID.Value Requery() thisform.lFindMode = .F. ENDIF .cmdfind.Enabled = .T. .txtOrderID.Enabled = .F. .Refresh() .Lockscreen = .F. ENDWITH ENDIF ENDPROC SQL SQL se ha establecido claramente como el lenguaje estndar de base de datos relacinales. Hay numerosas versiones de SQL. La versin original se desarrollo en el laboratorio de investigacin de San Jose de IBM. Este lenguaje, originalmente denominado Sequel se implemento como parte del proyecto System R , a principios de 1970. El lenguaje Sequel ha evolucionado desde entonces y su nombre ha pasado a ser SQL (Structured Query Lenguaje) lenguaje estructurado de consultas. Actualmente, numerosos productos son compatibles con el lenguaje SQL. En 1986, ANSI(Instituto Nacional Americano de Normalizacin) e ISO(Organizacin Internacional de Normalizacin) publicaron una norma SQL, denominada SQL86. En 1987, IBM publico su propia norma de SQL corporativo, interfaz de base de datos para (Arquitecturas de aplicacin a sistemas) SAASQL. 24

En 1989 se pblico una norma extendida para SQL denominada SQL89, y actualmente los sistemas de base de datos son normalmente compatibles al menos con las caractersticas de SQL89. La versin actual de la norma SQLANSI/ISO es la norma SQL92 En este apartado presenta una versin general de SQL basada en las normas SQL89 y SQL92. se debe tener en cuenta que algunas implementaciones de SQL pueden ser compatibles solo con SQL89, no siendo con SQL92. SQL incorporado permite el acceso a una base de datos desde un programa escrito en un lenguaje anfitrin, pero no proporciona ninguna asistencia en la presentacin de los resultados al usuario o en la generacin de informes. La mayora de los productos comerciales relacionados con base de datos proporcionan un lenguaje a la hora de crear la interfaz de usuario y dar formato a los datos para la generacin de Informes. Estos lenguajes especiales se denominan lenguajes de cuarta generacin. Conclusin. Espero que usted no deje que ninguno de estos problemas lo disuada de migrar a SQL Server. S, es mucho trabajo. Pero es ms aburrido que complicado. Espero que este artculo le ahorre mucho tiempo al informarle de muchos de los problemas antes de que usted incluso comience. Respecto a tener un conjunto del cdigo que tenga acceso a una base de datos de VFP as como bases de datos cliente/servidor, no la recomiendo para el largo plazo. Hay un demasiado cdigo condicional requerido y duplicacin de las herramientas que se deben escribir para asegurarlo. Al final, usted terminar probablemente con un sistema que ser ineficaz con todos el software de soporte, aunque siempre podr superar la situacin agregando ms hardware. Yo usara vistas locales solamente si planeara definitivamente cambiar al servidor del SQL, Oracle, etctera. Despus de la etapa de prototipos, recomiendo que usted migre gradualmente su cdigo para trabajar remotamente solamente. La capacidad del SQL Server 7.0 para trabajar sobre los Windows 95/98 y NT y muchas caractersticas nuevas hacen la migracin de VFP un proceso mucho ms sencillo. Puede servir fcilmente como su solamente software de soporte, mientras que usa el motor de los datos de VFP para procesar los datos extrados del servidor. Juntos, hacen a un equipo perfecto.

25

También podría gustarte