TN043: Rutinas RFX
Nota:
La nota técnica siguiente no se ha actualizado desde que se incluyó por primera vez en la documentación en línea. Como resultado, algunos procedimientos y temas podrían estar obsoletos o ser incorrectos. Para obtener información más reciente, se recomienda buscar el tema de interés en el índice de la documentación en línea.
En esta nota se describe la arquitectura de intercambio de campos de registro (RFX). También describe cómo escribir un procedimiento RFX_.
Información general sobre intercambio de campos de registro
Todas las funciones de campo del conjunto de registros se realizan con código de C++. No hay recursos especiales ni macros mágicas. La esencia del mecanismo es una función virtual que se debe invalidar en cada clase de conjunto de registros derivada. Siempre se encuentra en este formato:
void CMySet::DoFieldExchange(CFieldExchange* pFX)
{
//{{AFX_FIELD_MAP(CMySet)
<recordset exchange field type call>
<recordset exchange function call>
//}}AFX_FIELD_MAP
}
Los comentarios de AFX de formato especial permiten a ClassWizard buscar y editar el código en esta función. El código que no es compatible con ClassWizard debe colocarse fuera de los comentarios de formato especial.
En el ejemplo anterior, <recordset_exchange_field_type_call> tiene el formato:
pFX->SetFieldType(CFieldExchange::outputColumn);
y <recordset_exchange_function_call> tiene el formato:
RFX_Custom(pFX, "Col2", m_Col2);
La mayoría de las funciones RFX_ tiene tres argumentos, como se muestra anteriormente, pero algunos (por ejemplo RFX_Text
y RFX_Binary
) tienen argumentos opcionales adicionales.
Puede incluirse más de un RFX_ en cada función DoDataExchange
.
Consulte "afxdb.h" para obtener una lista de todas las rutinas de intercambio de campos del conjunto de registros proporcionadas con MFC.
Las llamadas de campo del conjunto de registros son una forma de registrar ubicaciones de memoria (normalmente miembros de datos) para almacenar datos de campo para una clase CMySet
.
Notas
Las funciones de campo del conjunto de registros están diseñadas para funcionar solo con las clases CRecordset
. Por lo general, no son utilizables por ninguna otra clase MFC.
Los valores iniciales de los datos se establecen en el constructor estándar de C++, normalmente en un bloque con comentarios //{{AFX_FIELD_INIT(CMylSet)
y //}}AFX_FIELD_INIT
.
Cada función RFX_ debe admitir varias operaciones, desde devolver el estado desfasado del campo hasta archivar el campo como preparación para editar el campo.
Cada función que llama a DoFieldExchange
(por ejemplo SetFieldNull
, IsFieldDirty
), realiza su propia inicialización alrededor de la llamada a DoFieldExchange
.
Cómo funciona
No es necesario comprender lo siguiente para usar el intercambio de campos de registro. Sin embargo, comprender cómo funciona en segundo plano le ayudará a escribir su propio procedimiento de intercambio.
La función miembro DoFieldExchange
es muy similar a la función miembro Serialize
: se encarga de obtener o establecer datos en un formulario externo, o desde este (en este caso, columnas del resultado de una consulta de ODBC) desde los datos de miembro en la clase o hacia estos. El parámetro pFX es el contexto para realizar el intercambio de datos y es similar al parámetro CArchive en CObject::Serialize
. PFX (un objeto CFieldExchange
) tiene un indicador de operación, que es similar a la marca de dirección CArchive, pero constituye una generalización de ella. Una función RFX puede tener que admitir las siguientes operaciones:
BindParam
— Indicar dónde la ODBC debe recuperar los datos de parámetrosBindFieldToColumn
— Indicar dónde la ODBC debe recuperar o depositar los datos outputColumnFixup
— Establecer longitudesCString/CByteArray
, establecer el bit de estado NULLMarkForAddNew
— Marcar como desfasado si el valor ha cambiado desde la llamada a AddNewMarkForUpdate
— Marcar como desfasado si el valor ha cambiado desde la llamada a EditName
— Anexar nombres de campo para campos marcados como desfasadosNameValue
— Anexar "<column name>=" para los campos marcados como desfasadosValue
— Anexar "" seguido de separador, como ',' o ' 'SetFieldDirty
— Establecer el campo desfasado (es decir, cambiado) del bit de estadoSetFieldNull
— Establecer el bit de estado que indica el valor NULL para el campoIsFieldDirty
— Devolver el valor del bit de estado desfasadoIsFieldNull
— Devolver el valor del bit de estado nullIsFieldNullable
— Devolver TRUE si el campo puede contener valores NULLStoreField
— Archivar el valor del campoLoadField
— Volver a cargar el valor del campo archivadoGetFieldInfoValue
— Devolver información general en un campoGetFieldInfoOrdinal
— Devolver información general en un campo
Extensiones de usuario
Hay varias maneras de ampliar el mecanismo de RFX predeterminado. Puede
Agregar tipos de datos nuevos. Por ejemplo:
CBookmark
Agregue procedimientos de intercambio (RFX_) nuevos.
void AFXAPI RFX_Bigint(CFieldExchange* pFX, const char *szName, BIGINT& value);
Haga que la función miembro
DoFieldExchange
incluya condicionalmente llamadas RFX adicionales o cualquier otra instrucción de C++ válida.while (posExtraFields != NULL) { RFX_Text(pFX, m_listName.GetNext(posExtraFields), m_listValue.GetNext(posExtraValues)); }
Nota:
ClassWizard no puede editar tal código y solo se debe usar fuera de los comentarios de formato especial.
Escritura de RFX personalizado
Para escribir su propia función RFX personalizada, se recomienda copiar una función RFX existente y modificarla para sus propios fines. Seleccionar el RFX correcto que se copiará puede facilitar mucho su trabajo. Algunas funciones RFX tienen algunas propiedades únicas que debe tener en cuenta al decidir qué copiar.
RFX_Long
y RFX_Int
: estas son las funciones RFX más sencillas. El valor de datos no necesita ninguna interpretación especial y el tamaño de los datos es fijo.
RFX_Single
y RFX_Double
: al igual que RFX_Long y RFX_Int anteriores, estas funciones son sencillas y pueden usar ampliamente la implementación predeterminada. Se almacenan en dbflt.cpp en lugar de dbrfx.cpp; sin embargo, para habilitar la carga de la biblioteca de punto flotante en runtime solo cuando se hace referencia explícitamente a ellas.
RFX_Text
y RFX_Binary
: estas dos funciones prealcalizarán un búfer estático para contener información binaria o de cadena, y deben registrar estos búferes con ODBC SQLBindCol en lugar de registrar &value. Por este motivo, estas dos funciones tienen una gran cantidad de código de casos especiales.
RFX_Date
: ODBC devuelve información de fecha y hora en su propia estructura de datos TIMESTAMP_STRUCT. Esta función asigna dinámicamente una TIMESTAMP_STRUCT como un "proxy" para enviar y recibir datos de fecha y hora. Varias operaciones deben transferir la información de fecha y hora entre el objeto de C++ CTime
y el proxy TIMESTAMP_STRUCT. Esto complica considerablemente esta función, pero es un buen ejemplo de cómo usar un proxy para la transferencia de datos.
RFX_LongBinary
: esta es la única función RFX de biblioteca de clases que no usa el enlace de columnas para recibir y enviar datos. Esta función omite la operación BindFieldToColumn y, en su lugar, durante la operación Fixup, asigna almacenamiento para contener los datos entrantes SQL_LONGVARCHAR o SQL_LONGVARBINARY y, a continuación, realiza una llamada SQLGetData para recuperar el valor en el almacenamiento asignado. Al prepararse para enviar valores de datos de vuelta al origen de datos (como en las operaciones NameValue y Value), esta función usa la funcionalidad DATA_AT_EXEC de ODBC. Consulte la Nota técnica 45 para obtener más información sobre cómo trabajar con SQL_LONGVARBINARY y SQL_LONGVARCHAR.
Al escribir su propia función RFX_, a menudo podrá usar CFieldExchange::Default
para implementar una operación determinada. Examine la implementación de Default para la operación en cuestión. Si realiza la operación, escribiría en la función RFX_ que delega a CFieldExchange::Default
. Puede ver ejemplos de llamadas a CFieldExchange::Default
en dbrfx.cpp.
Es importante llamar a IsFieldType
al principio de la función RFX y devolver inmediatamente si devuelve FALSE. Este mecanismo impide que las operaciones de parámetro se realicen en outputColumns y viceversa (como llamar a BindParam
en una outputColumn). Además, IsFieldType
realiza un seguimiento automático del recuento de outputColumns (m_nFields) y de los parámetros (m_nParams).