¿Funciona Visual FoxPro 9 en Windows 10?

Artículo original: Does Microsoft Visual FoxPro 9 run on Windows 10?
http://mattslay.com/does-microsoft-visual-foxpro-run-on-windows-10
Autor: Matt Slay
Traducido por: Luis María Guayán

Estoy seguro que muchos desarrolladores empedernidos de FoxPro tienen la curiosidad si Visual FoxPro 9.0 SP 2 se instalará y ejecutará en Windows 10. Bueno, yo quería ser uno de los primeros en descubrirlo, al igual que lo hice antes cuando Windows 8 fue lanzado por primera vez en su primera vista previa.

Por lo tanto vamos a averiguarlo...

En primer lugar, he instalado Windows 10 Preview (64 bits) en una partición de BootCamp en mis 15" MacBook Pro. (No se preocupen por estas cosas de Mac, es sólo Windows corriendo en hardware vivo, como si fuera una computadora Dell o HP). Eso salió muy bien e hice una instalación completa, quitando el Windows 8 que había estado utilizando en esa partición, en vez de actualizar desde Windows 8 a Windows 10.

A continuación, inserté con cuidado el CD de Visual FoxPro 9 que aún tengo desde 2004. En primer lugar, me impulsó a instalar unos "requisitos previos", cosa que hizo sin problemas. Luego seguí con la instalación principal de VFP y escogí todos los valores predeterminados, entonces el CD giraba y paraba un poco, y finalmente, me mostró una pantalla con un lindo mensaje indicando "Instalación completa" y "No hubo ningún error durante la instalación." Hasta ahora se ve bien!


Cómo añadir un generador a sus clases


Articulo original: How to add a Builder to your Class
http://weblogs.foxite.com/bernardbout/2014/09/18/how-to-add-a-builder-to-your-class
Autor: Bernard Bout
Traductor: Luis María Guayán

Es posible que haya visto que varias de mis clases vienen con un generador (builder) incorporado que hace mas fácil configurar las propiedades correctas y brinda una visión correcta de cómo se verá el objeto con las propiedades ya establecidas.

Recientemente uno de los chicos de Foxite ha creado una clase Spinner ideal para tocar con dedos grandes y yo le envié un Generador para ello. Me pidió un tutorial sobre cómo crear un generador así, y como también había estado pensando que esto sería útil, me decidí a documentar el proceso aquí. Nosotros vamos a usar la clase Spinner creada por Tony Vignone para esto (todo está incluido en la descarga) o Ud. puede utilizar cualquier otra clase que desee.

Una clase visual personalizada puede tener una serie de propiedades que necesitan configurarse, y es útil que el usuario final tenga todo esto en un solo lugar, en vez de una larga lista. Así que lo primero que hay que hacer es agregar las propiedades que el usuario puede cambiar, en la solapa Favoritos. De esta manera las propiedades que cambian, son independientes de las propiedades internas y que no cambian.

Para esto la clase necesita tener MemberData. Así que este es el primer paso en la creación de la clase.

1. Abra la clase y agregue una propiedad personalizada _memberdata [guión bajo - memberdata]




1.2. En la hoja de propiedades, seleccione cada propiedad para ser agregada a la solapa Favoritos, haga clic derecho sobre ella y en el menú emergente seleccione "Agregar a favoritos"

2. Añada otra propiedad personalizada a su clase y nómbrela _BigSpinnerBuilder. Darle un valor inicial de 0 [cero]. Haga clic derecho sobre ella, y añadirla a la solapa de Favoritos.

3. Haga clic derecho sobre esta nueva propiedad _BigSpinnerBuilder y seleccione "Editor MemberData" en la ventana emergente, y se abre el Editor MemberData. Configurarlo como en la siguiente imagen, haga clic en el icono de lupa y en la ventana de código que se abre, pegar el siguiente código:

nControls = ASelObj(aObjects)
If nControls # 0
   oObject = aObjects(1)
   Set Classlib To (oObject.ClassLibrary)
    IF VARTYPE(_screen.oWiz) = "U"
       _screen.addproperty("oWiz","")
    ENDIF
   _screen.oWiz = Createobject("BigSpinnerBuilder", oObject)
   _screen.oWiz.Show()
EndIf


Buscar registros repetidos

¿Quien no tuvo la tarea de buscar registros repetidos en una tabla de Visual FoxPro?...

Una forma de saber si tenemos registros repetidos en nuestras tablas es utilizar una sentencia SELECT con las cláusulas GROUP BY y HAVING como la siguiente:

OPEN DATABASE (HOME(2) + "Northwind\Northwind")
SELECT TerritoryDescription, ;
  COUNT(*) AS Repetido  ;
  FROM Territories ;
  GROUP BY TerritoryDescription ;
  HAVING Repetido > 1

El resultado de esta consulta nos muestra si existen registros repetidos y la cantidad de veces que se repiten.

Pero hay veces que necesitamos saber exactamente que registros están repetidos, para ello podemos utilizar algunas de las siguientes sentencias SELECT:

1)
OPEN DATABASE (HOME(2) + "Northwind\Northwind")
SELECT * ;
  FROM Territories ;
  WHERE TerritoryDescription IN ;
  (SELECT TerritoryDescription ;
  FROM Territories ;
  GROUP BY TerritoryDescription ;
  HAVING COUNT(*) > 1)

2)
OPEN DATABASE (HOME(2) + "Northwind\Northwind")
SELECT * ;
  FROM Territories T1;
  WHERE EXISTS ;
  (SELECT * ;
  FROM Territories T2 ;
  WHERE T1.TerritoryDescription = T2.TerritoryDescription ;
  GROUP BY T2.TerritoryDescription ;
  HAVING COUNT(*) > 1)

Nota: Las pruebas estan realizadas con la tabla "Territories" de la base de datos "Northwind" que viene en los ejemplos de VFP8 y superior.

Luis María Guayán

Manipular valores NULL en VFP

Artículo original: Handling NULL Values in VFP
http://weblogs.foxite.com/andykramek/archive/2005/12/04/1016.aspx
Autor: Andy Kramek
Traducido por: Ana María Bisbé York

El otro día estuve recordando algunos de los problemas que podían surgir en mi código cuando se encontraba un valor NULL inesperado. Esto me hizo retomar temas de comprensión sobre la manipulación de NULL en VFP y sobre esto tratará este blog. Vamos a comenzar considerando los posibles estados en los que puede existir un valor de VFP ( ya sea un campo de una tabla, o una variable). En Visual FoxPro hay en realidad tres condiciones:
  • el valor puede ser igual a algo (.T.)
  • el valor puede no ser igual a algo (.F.)
  • el valor puede estar en un estado en el que su valor no puede ser determinado (NULL)
Los primeros dos casos no tienen problema y podemos controlar estos casos diariamente en nuestro código. Es el tercero el que nos puede causar problemas, sin que lo controlemos. Frecuentemente encuentro útil, pensar NULL pensando que NULL significa "Yo no se". Esto ayuda a tener sentido el comportamiento de los valores nulos cuando son encontrados.

Lo primero a recordar sobre los nulos es que la respuesta a cualquier comparación que involucre un valor NULL es siempre NULL. Consideremos el siguiente código:
luVal = NULL
? luVal > 0
? luVal = "UNA CADENA DE CARACTERES"
? luVal <= DATE()
? luVal = .T.
El valor devuelto en cada caso es realmente NULL. En otras palabras, cuando VFP pregunta cómo un NULL ( igual a "Yo no se") relaciona con algún otro valor, la respuesta siempre es NULL ( igual a "Yo no se"). Ahora puede estar pensando que esto es un ejemplo tonto, porque siempre puede verificar el tipo de variable (o campo) empleando las funciones TYPE() o VARTYPE().

Desafortunadamente TYPE() no está recomendada para verificar valores NULL, ya que devuelve un tipo "L" para una variable que haya sido inicializada como NULL, de esta forma:
luVal = NULL
? TYPE("luVal") && Devuelve "L"
Devolverá el tipo de dato original si la variable está contenida originalmente algún valor no nulo y luego adquiere un NULL, así:
lnTotal = 100
luVal = 10
? TYPE( "luVal" ) && Type = "N"
luVal = IIF( luVal > 20, luVal, NULL ) 
? TYPE( "luVal" ) && Value = NULL pero Type = "N"
lnTotal = lnTotal + luVal && lnTotal = NULL - ni siquiera 100!!!
¿Por qué es malo? Considere qué podría ocurrir si va a utilizar código que acumula valores dentro de un lazo (por ejemplo un SCAN) y un registro contiene un NULL. No sólo el total se pierde, sino que no va a recuperar los valores, porque tan pronto como alcance un valor nulo en el acumulador quedará NULL y todas las sumas subsecuentes van a resultar simplemente NULL. Puede que no reciba un error; pero no va a obtener el resultado deseado.

VARTYPE() tiene un comportamiento definitivamente mejor en este tema. De forma predeterminada devuelve un tipo de "X" si el valor verificado contiene NULL, sin embargo, al pasar el segundo parámetro como .T. puede obtener el tipo de dato original (en otras palabras, imita el comportamiento de TYPE()).

En la práctica, la mejor forma de controlar los nulos es verificarlos explícitamente empleando la función ISNULL() (que devuelve .T. si el valor verificado es nulo) o envolver expresiones que pueden contener nulos dentro de NVL(), de tal forma que cada valor nulo se reemplaza con un valor que sea más fácil de controlar. (De hecho, fue una omisión de la función NVL() lo que me ocasionó problemas esta semana y por tanto provocó este escrito.)

NVL() es simplemente una función que sustituye un valor especificado cuando se encuentra un NULL, así:
luVal = NULL
? NVL( luVal, 0 ) && Devuelve 0, no NULL!
Afortunadamente PUEDE utilizar funciones tales como SUM() y las funciones CALCULATE, o un SQL SUM(), incluso cuando hay valores NULL. Visual FoxPro es lo suficientemente inteligente como para ignorar esos valores - y esto incluso es uno de los beneficios de los valores NULL, al calcular promedios y contar registros - los NULLs se ignoran y no afectan el resultado.

Luego de haber dicho esto, ¿cuál es mi problema? Olvidé que cuando estamos concatenando cadenas recortadas (trimmed) de caracteres, uno de los cuales contiene un NULL, el resultado es NULL. La situación que tuve fue al llamar a un procedimiento almacenado en SQL Server que devolvía un valor en un cursor. Se suponía que el valor era una cadena que contenía hasta 6 caracteres espacios. Esto fue recortado, y provocó que se generara un nombre de archivo al concatenarlo con el ID de usuario que había iniciado sesión. Era algo así:
lcNextSeq = ALLTRIM( cur_result.cNextSeq ) && Este campo era NULL
lcFileName = lcUserID + lcNextSeq
El problema surgió cuando el procedimiento almacenado devolvió NULL, debido a que la operación de inserción previa había fallado y no tenía forma de atrapar el resultado en una función NVL(). No generaba un error; pero el resultado era NULL. Ahora, yo pienso que esto es un bug (quizás se introdujo en el producto desde VFP 6.0 al menos). Este código muestra por qué:
lcVal = ALLTRIM(NULL)
? lcVal && .NULL.
luVal = NULL
? luVal && .NULL.
? "Test" + lcVal && .NULL.
? "Test" + luVal && OPERATOR/OPERAND MISMATCH!!!!
Después de todo, si hay un error cuando una cadena de caracteres se concatena con una que contenga un NULL, entonces, simplemente aplicando una función ALLTRIM() debería no permitir que la operación se ejecute sin devolver error.

La moraleja de esta historia es, por supuesto, ¡ Controle siempre sus NULLs !

Incidentalmente puede estar pensando que como sólo utiliza datos VFP no se admiten nulos en sus tablas, este es el tipo de cosas que no le va a ocurrir. Está es lo cierto, mientras no utilice ni un JOIN en una consulta SQL. Recuerde que en ese tipo de consultas se devuelve un valor NULL como resultado si no hay coincidencia en los registros - independientemente de si sus tablas admiten nulos o no.