TN053: Personalizar las rutinas DFX para las clases de base de datos DAO
Nota:
DAO se usa con bases de datos de Access y es compatible con Office 2013. DAO 3.6 es la versión final y se considera obsoleta. El entorno y los asistentes de Visual C++ no admiten DAO (aunque se incluyen las clases DAO y todavía se pueden usar). Microsoft recomienda usar plantillas OLE DB o bien ODBC y MFC para proyectos nuevos. Solo debe usar DAO para mantener las aplicaciones existentes.
En esta nota técnica, se describe el mecanismo de intercambio de campos de registros DAO (DFX). Para ayudar a comprender lo que sucede en las rutinas DFX, se explicará con detalle la función DFX_Text
como ejemplo. Como fuente adicional de información de esta nota técnica, puede examinar el código de las demás funciones DFX individuales. Probablemente no necesitará una rutina DFX personalizada con tanta frecuencia como sea posible que necesite una rutina RFX personalizada (usada con clases de base de datos ODBC).
Esta nota técnica contiene:
Introducción a DFX
Ejemplos de intercambio de campos de registros DAO y enlace dinámico
Introducción a DFX
El mecanismo de intercambio de campos de registros DAO (DFX) se usa para simplificar el procedimiento de recuperación y actualización de datos al usar la clase CDaoRecordset
. El proceso se simplifica mediante miembros de datos de la clase CDaoRecordset
. Al derivar de CDaoRecordset
, puede agregar miembros de datos a la clase derivada que representa cada campo de una tabla o consulta. Este mecanismo de "enlace estático" es sencillo, pero es posible que no sea el método de recuperación y actualización de datos que se elija para todas las aplicaciones. DFX recupera cada campo enlazado cada vez que se cambia el registro actual. Si está desarrollando una aplicación sensible al rendimiento que no requiere recuperar todos los campos cuando hay cambios, el "enlace dinámico" mediante CDaoRecordset::GetFieldValue
y CDaoRecordset::SetFieldValue
puede ser el método de acceso a datos que prefiera.
Nota:
DFX y el enlace dinámico no son mutuamente excluyentes, por lo que se puede utilizar un uso híbrido del enlace estático y dinámico.
Ejemplo 1: uso solo del intercambio de campos de registro DAO
(se supone que el elemento CMySet
de la clase derivada de CDaoRecordset
ya está abierto)
// Add a new record to the customers table
myset.AddNew();
myset.m_strCustID = _T("MSFT");
myset.m_strCustName = _T("Microsoft");
myset.Update();
Ejemplo 2: uso solo del enlace dinámico
(se supone que se usa la clase CDaoRecordset
y que rs
ya está abierto)
// Add a new record to the customers table
COleVariant varFieldValue1 (_T("MSFT"),
VT_BSTRT);
//Note: VT_BSTRT flags string type as ANSI,
instead of UNICODE default
COleVariant varFieldValue2 (_T("Microsoft"),
VT_BSTRT);
rs.AddNew();
rs.SetFieldValue(_T("Customer_ID"),
varFieldValue1);
rs.SetFieldValue(_T("Customer_Name"),
varFieldValue2);
rs.Update();
Ejemplo 3: uso del intercambio de campos de registros DAO y el enlace dinámico
(se supone que se examinan los datos de los empleados emp
con la clase derivada de CDaoRecordset
)
// Get the employee's data so that it can be displayed
emp.MoveNext();
// If user wants to see employee's photograph,
// fetch it
COleVariant varPhoto;
if (bSeePicture)
emp.GetFieldValue(_T("photo"),
varPhoto);
// Display the data
PopUpEmployeeData(emp.m_strFirstName,
emp.m_strLastName,
varPhoto);
Funcionamiento de DFX
El mecanismo de DFX funciona de forma similar al mecanismo de intercambio de campos de registros (RFX) utilizado por las clases ODBC de MFC. Los principios de DFX y RFX son los mismos, pero hay numerosas diferencias internas. El diseño de las funciones DFX era de modo que prácticamente todo el código se comparte con las rutinas DFX individuales. En el nivel más alto, DFX solo hace algunas cosas.
DFX construye la cláusula SELECT y la cláusula PARAMETERS de SQL si es necesario.
DFX construye la estructura de enlace usada por la función
GetRows
de DAO (más información sobre esto más adelante).DFX administra el búfer de datos usado para detectar campos modificados (si se usa el almacenamiento en búfer doble)
DFX administra las matrices de estado NULL y DIRTY y establece los valores si es necesario en las actualizaciones.
En el corazón del mecanismo de DFX, se encuentra la función DoFieldExchange
de la clase derivada de CDaoRecordset
. Esta función envía las llamadas a las funciones DFX individuales de un tipo de operación adecuado. Antes de llamar a DoFieldExchange
, las funciones internas de MFC establecen el tipo de operación. En la lista siguiente, se muestran los distintos tipos de operación y una breve descripción.
Operación | Descripción |
---|---|
AddToParameterList |
Crea la cláusula PARAMETERS. |
AddToSelectList |
Crea la cláusula SELECT. |
BindField |
Configura la estructura del enlace. |
BindParam |
Establece los valores de los parámetros. |
Fixup |
Establece el estado NULL. |
AllocCache |
Asigna la memoria caché para la comprobación de modificaciones. |
StoreField |
Guarda el registro actual en la memoria caché. |
LoadField |
Restaura la memoria caché en los valores de los miembros. |
FreeCache |
Libera la memoria caché. |
SetFieldNull |
Establece el estado y el valor del campo en NULL. |
MarkForAddNew |
Marca los campos modificados si no son PSEUDO NULL. |
MarkForEdit |
Marca los campos modificados si no coinciden con la memoria caché. |
SetDirtyField |
Establece los valores de campo marcados como con modificaciones. |
En la sección siguiente, se explicará cada operación con más detalle para DFX_Text
.
La característica más importante que se debe comprender sobre el proceso de intercambio de campos de registros DAO es que usa la función GetRows
del objeto CDaoRecordset
. La función GetRows
de DAO puede funcionar de varias maneras. Esta nota técnica solo describirá GetRows
brevemente, ya que está fuera del ámbito de esta nota técnica.
La función GetRows
de DAO puede funcionar de varias maneras.
Puede recuperar varios registros y varios campos de datos a la vez. Esto permite un acceso más rápido a los datos con la complicación de tratar con una estructura de datos grande y los desplazamientos adecuados para cada campo y para cada registro de datos de la estructura. MFC no aprovecha este mecanismo de recuperación de varios registros.
Otra manera de trabajar con
GetRows
es permitir que los programadores especifiquen direcciones de enlace para los datos recuperados de cada campo de un registro de datos.DAO también realizará una "devolución de llamada" al autor de la llamada para las columnas de longitud variable con el fin de permitir que el autor de la llamada asigne memoria. Esta segunda característica tiene la ventaja de minimizar el número de copias de datos, así como permitir el almacenamiento directo de los datos en los miembros de una clase (la clase derivada de
CDaoRecordset
). Este segundo mecanismo es el método que usa MFC para enlazar a miembros de datos en las clases derivadas deCDaoRecordset
.
Qué hace la rutina DFX personalizada
Se desprende de esta explicación que la operación más importante implementada en cualquier función DFX debe ser la capacidad de configurar las estructuras de datos necesarias para llamar correctamente a GetRows
. Hay una serie de otras operaciones que una función DFX también debe admitir, pero ninguna tan importante o compleja como preparar correctamente la llamada a GetRows
.
El uso de DFX se describe en la documentación en línea. Básicamente, hay dos requisitos. En primer lugar, se deben agregar los miembros a la clase derivada de CDaoRecordset
para cada campo y parámetro enlazados. Después de esto, se debe invalidar CDaoRecordset::DoFieldExchange
. Tenga en cuenta que el tipo de datos del miembro es importante. Debe coincidir con los datos del campo de la base de datos o al menos ser convertibles a ese tipo. Por ejemplo, un campo numérico de la base de datos, como un entero largo, siempre se puede convertir en texto y enlazarse a un miembro CString
, pero un campo de texto de una base de datos puede no convertirse necesariamente en una representación numérica, como un entero largo y enlazarse a un miembro de tipo entero largo. DAO y el motor de base de datos Microsoft Jet son responsables de la conversión (en lugar de MFC).
Detalles de DFX_Text
Como se mencionó anteriormente, la mejor manera de explicar cómo funciona DFX es trabajar con un ejemplo. Para este propósito, los aspectos internos de DFX_Text
deben funcionar bastante bien para ayudar a proporcionar al menos un conocimiento básico de DFX.
AddToParameterList
Esta operación crea la cláusula PARAMETERS de SQL ("
Parameters <param name>, <param type> ... ;
") requerida por Jet. Cada parámetro tiene un nombre y un tipo (como se especifica en la llamada a RFX). Consulte la funciónCDaoFieldExchange::AppendParamType
para ver los nombres de los tipos individuales. En el caso deDFX_Text
, el tipo utilizado es text.AddToSelectList
Crea la cláusula SELECT de SQL. Esto es bastante directo, ya que simplemente se anexa el nombre de columna especificado por la llamada a DFX ("
SELECT <column name>, ...
").BindField
Las más compleja de las operaciones. Como se mencionó anteriormente, aquí es donde se configura la estructura de enlace de DAO utilizada por
GetRows
. Como puede ver en el código deDFX_Text
, los tipos de información de la estructura incluyen el tipo DAO usado (DAO_CHAR o DAO_WCHAR en el caso deDFX_Text
). Además, también se configura el tipo de enlace usado. En una sección anterior, se describió brevementeGetRows
, solo lo suficiente explicar que el tipo de enlace usado por MFC siempre es el enlace de dirección directo (DAOBINDING_DIRECT). Además, para el enlace de columna de longitud variable (comoDFX_Text
) se usa el enlace de devolución de llamada para que MFC pueda controlar la asignación de memoria y especificar una dirección de la longitud correcta. Esto significa que MFC siempre puede indicar a DAO "dónde" colocar los datos, lo que permite enlazar directamente a las variables miembro. El resto de la estructura de enlace se rellena con elementos como la dirección de la función de devolución de llamada de asignación de memoria y el tipo de enlace de columna (enlace por nombre de columna).BindParam
Se trata de una operación sencilla que llama a
SetParamValue
con el valor de parámetro especificado en el miembro del parámetro.Fixup
Rellena el estado NULL de cada campo.
SetFieldNull
Esta operación solo marca el estado de cada campo como NULL y establece el valor de la variable miembro en PSEUDO_NULL.
SetDirtyField
Llama a
SetFieldValue
para cada campo marcado como con modificaciones.
Todas las operaciones restantes solo tratan con el uso de la memoria caché de datos. La memoria caché de datos es un búfer adicional de los datos del registro actual que se usa para simplificar ciertas cosas. Por ejemplo, se pueden detectar automáticamente los campos "con modificaciones". Como se describe en la documentación en línea, se puede desactivar completamente y también en el nivel de campo. La implementación del búfer utiliza un mapa. Este mapa se usa para hacer coincidir las copias asignadas dinámicamente de los datos con la dirección del campo "enlazado" (o miembro de datos derivado de CDaoRecordset
).
AllocCache
Asigna dinámicamente el valor del campo almacenado en caché y lo agrega al mapa.
FreeCache
Elimina el valor del campo almacenado en caché y lo quita del mapa.
StoreField
Copia el valor del campo actual en la memoria caché de datos.
LoadField
Copia el valor almacenado en caché en el miembro de campo.
MarkForAddNew
Comprueba si el valor del campo actual no es NULL y lo marca como con modificaciones si es necesario.
MarkForEdit
Compara el valor del campo actual con la memoria caché de datos y lo marca como con modificaciones si es necesario.
Sugerencia
Modele las rutinas DFX personalizadas en las rutinas DFX existentes para los tipos de datos estándar.