Acceso a datos mediante ADO.NET (C++/CLI)
ADO.NET es la API .NET Framework para el acceso a datos y proporciona potencia y facilidad de uso que no tienen las soluciones de acceso a datos anteriores. En esta sección se describen algunos de los problemas relacionados con ADO.NET que son únicos para Visual C++ usuarios, como serializar tipos nativos.
ADO.NET se ejecuta en Common Language Runtime (CLR). Por lo tanto, cualquier aplicación que interactúe con ADO.NET también debe tener como destino CLR. Sin embargo, esto no significa que las aplicaciones nativas no puedan usar ADO.NET. En estos ejemplos se muestra cómo interactuar con una base de ADO.NET desde código nativo.
Serializar cadenas ANSI para ADO.NET
Muestra cómo agregar una cadena nativa ( ) a una base de datos y cómo serializar system.string de una base de datos char * a una cadena nativa. char *
Ejemplo
En este ejemplo, se crea la clase DatabaseClass para interactuar con un ADO.NET objeto DataTable. Tenga en cuenta que esta clase es una C++ class nativa (en comparación con ref class o value class ). Esto es necesario porque queremos usar esta clase desde código nativo y no se pueden usar tipos administrados en código nativo. Esta clase se compilará para tener como destino CLR, como indica la #pragma managed directiva anterior a la declaración de clase. Para obtener más información sobre esta directiva, vea managed, unmanaged.
Tenga en cuenta el miembro privado de la clase DatabaseClass: gcroot<DataTable ^> table . Puesto que los tipos nativos no pueden contener tipos administrados, gcroot la palabra clave es necesaria. Para obtener más información sobre gcroot , gcroot
El resto del código de este ejemplo es código nativo de C++, como se indica en la #pragma unmanaged directiva anterior main a . En este ejemplo, vamos a crear una nueva instancia de DatabaseClass y llamar a sus métodos para crear una tabla y rellenar algunas filas de la tabla. Tenga en cuenta que las cadenas nativas de C++ se pasan como valores para la columna de base de datos StringCol. Dentro de DatabaseClass, estas cadenas se serializan en cadenas administradas mediante la funcionalidad de serialización que se encuentra en el espacio de nombres System.Runtime.InteropServices. En concreto, el método PtrToStringAnsi se usa para serializar un objeto a una cadena y el método StringToHGlobalAnsise usa para serializar una cadena en .
Nota
La memoria asignada por StringToHGlobalAnsi se debe desasignar llamando a FreeHGlobal o .
// adonet_marshal_string_native.cpp
// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll
#include <comdef.h>
#include <gcroot.h>
#include <iostream>
using namespace std;
#using <System.Data.dll>
using namespace System;
using namespace System::Data;
using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managed
class DatabaseClass
{
public:
DatabaseClass() : table(nullptr) { }
void AddRow(char *stringColValue)
{
// Add a row to the table.
DataRow ^row = table->NewRow();
row["StringCol"] = Marshal::PtrToStringAnsi(
(IntPtr)stringColValue);
table->Rows->Add(row);
}
void CreateAndPopulateTable()
{
// Create a simple DataTable.
table = gcnew DataTable("SampleTable");
// Add a column of type String to the table.
DataColumn ^column1 = gcnew DataColumn("StringCol",
Type::GetType("System.String"));
table->Columns->Add(column1);
}
int GetValuesForColumn(char *dataColumn, char **values,
int valuesLength)
{
// Marshal the name of the column to a managed
// String.
String ^columnStr = Marshal::PtrToStringAnsi(
(IntPtr)dataColumn);
// Get all rows in the table.
array<DataRow ^> ^rows = table->Select();
int len = rows->Length;
len = (len > valuesLength) ? valuesLength : len;
for (int i = 0; i < len; i++)
{
// Marshal each column value from a managed string
// to a char *.
values[i] = (char *)Marshal::StringToHGlobalAnsi(
(String ^)rows[i][columnStr]).ToPointer();
}
return len;
}
private:
// Using gcroot, you can use a managed type in
// a native class.
gcroot<DataTable ^> table;
};
#pragma unmanaged
int main()
{
// Create a table and add a few rows to it.
DatabaseClass *db = new DatabaseClass();
db->CreateAndPopulateTable();
db->AddRow("This is string 1.");
db->AddRow("This is string 2.");
// Now retrieve the rows and display their contents.
char *values[MAXCOLS];
int len = db->GetValuesForColumn(
"StringCol", values, MAXCOLS);
for (int i = 0; i < len; i++)
{
cout << "StringCol: " << values[i] << endl;
// Deallocate the memory allocated using
// Marshal::StringToHGlobalAnsi.
GlobalFree(values[i]);
}
delete db;
return 0;
}
StringCol: This is string 1.
StringCol: This is string 2.
Compilar el código
Para compilar el código desde la línea de comandos, guarde el ejemplo de código en un archivo denominado adonet_marshal_string_native.cpp y escriba la siguiente instrucción:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_native.cpp
Serializar cadenas BSTR para ADO.NET
Muestra cómo agregar una cadena COM ( ) a una base de datos y cómo serializar BSTRBSTR de una base de datos a BSTR .
Ejemplo
En este ejemplo, se crea la clase DatabaseClass para interactuar con un ADO.NET objeto DataTable. Tenga en cuenta que esta clase es una C++ class nativa (en comparación con ref class o value class ). Esto es necesario porque queremos usar esta clase desde código nativo y no se pueden usar tipos administrados en código nativo. Esta clase se compilará para tener como destino CLR, como indica la #pragma managed directiva anterior a la declaración de clase. Para obtener más información sobre esta directiva, vea managed, unmanaged.
Tenga en cuenta el miembro privado de la clase DatabaseClass: gcroot<DataTable ^> table . Puesto que los tipos nativos no pueden contener tipos administrados, gcroot la palabra clave es necesaria. Para obtener más información sobre gcroot , gcroot
El resto del código de este ejemplo es código nativo de C++, como se indica en la #pragma unmanaged directiva anterior main a . En este ejemplo, vamos a crear una nueva instancia de DatabaseClass y llamar a sus métodos para crear una tabla y rellenar algunas filas de la tabla. Tenga en cuenta que las cadenas COM se pasan como valores para la columna de base de datos StringCol. Dentro de DatabaseClass, estas cadenas se serializan en cadenas administradas mediante la funcionalidad de serialización que se encuentra en el espacio de nombres System.Runtime.InteropServices. En concreto, el método PtrToStringBSTR se usa para serializar un objeto a una cadena y el método StringToBSTRse usa para serializar una cadena en .
Nota
La memoria asignada por StringToBSTR se debe desasignar llamando a FreeBSTR o .
// adonet_marshal_string_bstr.cpp
// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll
#include <comdef.h>
#include <gcroot.h>
#include <iostream>
using namespace std;
#using <System.Data.dll>
using namespace System;
using namespace System::Data;
using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managed
class DatabaseClass
{
public:
DatabaseClass() : table(nullptr) { }
void AddRow(BSTR stringColValue)
{
// Add a row to the table.
DataRow ^row = table->NewRow();
row["StringCol"] = Marshal::PtrToStringBSTR(
(IntPtr)stringColValue);
table->Rows->Add(row);
}
void CreateAndPopulateTable()
{
// Create a simple DataTable.
table = gcnew DataTable("SampleTable");
// Add a column of type String to the table.
DataColumn ^column1 = gcnew DataColumn("StringCol",
Type::GetType("System.String"));
table->Columns->Add(column1);
}
int GetValuesForColumn(BSTR dataColumn, BSTR *values,
int valuesLength)
{
// Marshal the name of the column to a managed
// String.
String ^columnStr = Marshal::PtrToStringBSTR(
(IntPtr)dataColumn);
// Get all rows in the table.
array<DataRow ^> ^rows = table->Select();
int len = rows->Length;
len = (len > valuesLength) ? valuesLength : len;
for (int i = 0; i < len; i++)
{
// Marshal each column value from a managed string
// to a BSTR.
values[i] = (BSTR)Marshal::StringToBSTR(
(String ^)rows[i][columnStr]).ToPointer();
}
return len;
}
private:
// Using gcroot, you can use a managed type in
// a native class.
gcroot<DataTable ^> table;
};
#pragma unmanaged
int main()
{
// Create a table and add a few rows to it.
DatabaseClass *db = new DatabaseClass();
db->CreateAndPopulateTable();
BSTR str1 = SysAllocString(L"This is string 1.");
db->AddRow(str1);
BSTR str2 = SysAllocString(L"This is string 2.");
db->AddRow(str2);
// Now retrieve the rows and display their contents.
BSTR values[MAXCOLS];
BSTR str3 = SysAllocString(L"StringCol");
int len = db->GetValuesForColumn(
str3, values, MAXCOLS);
for (int i = 0; i < len; i++)
{
wcout << "StringCol: " << values[i] << endl;
// Deallocate the memory allocated using
// Marshal::StringToBSTR.
SysFreeString(values[i]);
}
SysFreeString(str1);
SysFreeString(str2);
SysFreeString(str3);
delete db;
return 0;
}
StringCol: This is string 1.
StringCol: This is string 2.
Compilar el código
Para compilar el código desde la línea de comandos, guarde el ejemplo de código en un archivo denominado adonet_marshal_string_native.cpp y escriba la siguiente instrucción:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_native.cpp
Serializar cadenas Unicode para ADO.NET
Muestra cómo agregar una cadena Unicode nativa ( ) a una base de datos y cómo serializar system.string desde una base de datos wchar_t * a una cadena Unicode nativa. wchar_t *
Ejemplo
En este ejemplo, se crea la clase DatabaseClass para interactuar con un ADO.NET objeto DataTable. Tenga en cuenta que esta clase es una C++ class nativa (en comparación con ref class o value class ). Esto es necesario porque queremos usar esta clase desde código nativo y no se pueden usar tipos administrados en código nativo. Esta clase se compilará para tener como destino CLR, como indica la #pragma managed directiva anterior a la declaración de clase. Para obtener más información sobre esta directiva, vea managed, unmanaged.
Tenga en cuenta el miembro privado de la clase DatabaseClass: gcroot<DataTable ^> table . Puesto que los tipos nativos no pueden contener tipos administrados, gcroot la palabra clave es necesaria. Para obtener más información sobre gcroot , gcroot
El resto del código de este ejemplo es código nativo de C++, como se indica en la #pragma unmanaged directiva anterior main a . En este ejemplo, vamos a crear una nueva instancia de DatabaseClass y llamar a sus métodos para crear una tabla y rellenar algunas filas de la tabla. Tenga en cuenta que las cadenas unicode de C++ se pasan como valores para la columna de base de datos StringCol. Dentro de DatabaseClass, estas cadenas se serializan en cadenas administradas mediante la funcionalidad de serialización que se encuentra en el espacio de nombres System.Runtime.InteropServices. En concreto, el método PtrToStringUni se usa para serializar un objeto a una cadena y el método StringToHGlobalUni se usa para serializar una cadena en .
Nota
La memoria asignada por StringToHGlobalUni se debe desasignar llamando a FreeHGlobal o .
// adonet_marshal_string_wide.cpp
// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll
#include <comdef.h>
#include <gcroot.h>
#include <iostream>
using namespace std;
#using <System.Data.dll>
using namespace System;
using namespace System::Data;
using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managed
class DatabaseClass
{
public:
DatabaseClass() : table(nullptr) { }
void AddRow(wchar_t *stringColValue)
{
// Add a row to the table.
DataRow ^row = table->NewRow();
row["StringCol"] = Marshal::PtrToStringUni(
(IntPtr)stringColValue);
table->Rows->Add(row);
}
void CreateAndPopulateTable()
{
// Create a simple DataTable.
table = gcnew DataTable("SampleTable");
// Add a column of type String to the table.
DataColumn ^column1 = gcnew DataColumn("StringCol",
Type::GetType("System.String"));
table->Columns->Add(column1);
}
int GetValuesForColumn(wchar_t *dataColumn, wchar_t **values,
int valuesLength)
{
// Marshal the name of the column to a managed
// String.
String ^columnStr = Marshal::PtrToStringUni(
(IntPtr)dataColumn);
// Get all rows in the table.
array<DataRow ^> ^rows = table->Select();
int len = rows->Length;
len = (len > valuesLength) ? valuesLength : len;
for (int i = 0; i < len; i++)
{
// Marshal each column value from a managed string
// to a wchar_t *.
values[i] = (wchar_t *)Marshal::StringToHGlobalUni(
(String ^)rows[i][columnStr]).ToPointer();
}
return len;
}
private:
// Using gcroot, you can use a managed type in
// a native class.
gcroot<DataTable ^> table;
};
#pragma unmanaged
int main()
{
// Create a table and add a few rows to it.
DatabaseClass *db = new DatabaseClass();
db->CreateAndPopulateTable();
db->AddRow(L"This is string 1.");
db->AddRow(L"This is string 2.");
// Now retrieve the rows and display their contents.
wchar_t *values[MAXCOLS];
int len = db->GetValuesForColumn(
L"StringCol", values, MAXCOLS);
for (int i = 0; i < len; i++)
{
wcout << "StringCol: " << values[i] << endl;
// Deallocate the memory allocated using
// Marshal::StringToHGlobalUni.
GlobalFree(values[i]);
}
delete db;
return 0;
}
StringCol: This is string 1.
StringCol: This is string 2.
Compilar el código
Para compilar el código desde la línea de comandos, guarde el ejemplo de código en un archivo denominado adonet_marshal_string_wide.cpp y escriba la siguiente instrucción:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_wide.cpp
Serializar una variant para ADO.NET
Muestra cómo agregar un nativo a una base de datos y cómo serializar VARIANTVARIANT de una base de datos a una VARIANT nativa.
Ejemplo
En este ejemplo, se crea la clase DatabaseClass para interactuar con un ADO.NET objeto DataTable. Tenga en cuenta que esta clase es una C++ class nativa (en comparación con ref class o value class ). Esto es necesario porque queremos usar esta clase desde código nativo y no se pueden usar tipos administrados en código nativo. Esta clase se compilará para tener como destino CLR, como indica la #pragma managed directiva anterior a la declaración de clase. Para obtener más información sobre esta directiva, vea managed, unmanaged.
Tenga en cuenta el miembro privado de la clase DatabaseClass: gcroot<DataTable ^> table . Puesto que los tipos nativos no pueden contener tipos administrados, gcroot la palabra clave es necesaria. Para obtener más información sobre gcroot , gcroot
El resto del código de este ejemplo es código nativo de C++, como se indica en la #pragma unmanaged directiva anterior main a . En este ejemplo, vamos a crear una nueva instancia de DatabaseClass y llamar a sus métodos para crear una tabla y rellenar algunas filas de la tabla. Tenga en cuenta que VARIANT los tipos nativos se pasan como valores para la columna de base de datos ObjectCol. Dentro de DatabaseClass, estos tipos se serializan en objetos administrados mediante la funcionalidad de serialización que se encuentra en el espacio de nombres VARIANTVARIANT En concreto, el método GetObjectForNativeVariant se usa para serializar un objeto a un objeto y el método GetNativeVariantForObjectse usa para serializar un objeto en .
// adonet_marshal_variant.cpp
// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll
#include <comdef.h>
#include <gcroot.h>
#include <iostream>
using namespace std;
#using <System.Data.dll>
using namespace System;
using namespace System::Data;
using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managed
class DatabaseClass
{
public:
DatabaseClass() : table(nullptr) { }
void AddRow(VARIANT *objectColValue)
{
// Add a row to the table.
DataRow ^row = table->NewRow();
row["ObjectCol"] = Marshal::GetObjectForNativeVariant(
IntPtr(objectColValue));
table->Rows->Add(row);
}
void CreateAndPopulateTable()
{
// Create a simple DataTable.
table = gcnew DataTable("SampleTable");
// Add a column of type String to the table.
DataColumn ^column1 = gcnew DataColumn("ObjectCol",
Type::GetType("System.Object"));
table->Columns->Add(column1);
}
int GetValuesForColumn(wchar_t *dataColumn, VARIANT *values,
int valuesLength)
{
// Marshal the name of the column to a managed
// String.
String ^columnStr = Marshal::PtrToStringUni(
(IntPtr)dataColumn);
// Get all rows in the table.
array<DataRow ^> ^rows = table->Select();
int len = rows->Length;
len = (len > valuesLength) ? valuesLength : len;
for (int i = 0; i < len; i++)
{
// Marshal each column value from a managed object
// to a VARIANT.
Marshal::GetNativeVariantForObject(
rows[i][columnStr], IntPtr(&values[i]));
}
return len;
}
private:
// Using gcroot, you can use a managed type in
// a native class.
gcroot<DataTable ^> table;
};
#pragma unmanaged
int main()
{
// Create a table and add a few rows to it.
DatabaseClass *db = new DatabaseClass();
db->CreateAndPopulateTable();
BSTR bstr1 = SysAllocString(L"This is a BSTR in a VARIANT.");
VARIANT v1;
v1.vt = VT_BSTR;
v1.bstrVal = bstr1;
db->AddRow(&v1);
int i = 42;
VARIANT v2;
v2.vt = VT_I4;
v2.lVal = i;
db->AddRow(&v2);
// Now retrieve the rows and display their contents.
VARIANT values[MAXCOLS];
int len = db->GetValuesForColumn(
L"ObjectCol", values, MAXCOLS);
for (int i = 0; i < len; i++)
{
switch (values[i].vt)
{
case VT_BSTR:
wcout << L"ObjectCol: " << values[i].bstrVal << endl;
break;
case VT_I4:
cout << "ObjectCol: " << values[i].lVal << endl;
break;
default:
break;
}
}
SysFreeString(bstr1);
delete db;
return 0;
}
ObjectCol: This is a BSTR in a VARIANT.
ObjectCol: 42
Compilar el código
Para compilar el código desde la línea de comandos, guarde el ejemplo de código en un archivo denominado adonet_marshal_variant.cpp y escriba la siguiente instrucción:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_variant.cpp
Serialización de safearray para ADO.NET
Muestra cómo agregar un nativo a una base de datos y cómo serializar una matriz administrada de una base de SAFEARRAY datos a una SAFEARRAY nativa.
Ejemplo
En este ejemplo, se crea la clase DatabaseClass para interactuar con un ADO.NET objeto DataTable. Tenga en cuenta que esta clase es una C++ class nativa (en comparación con ref class o value class ). Esto es necesario porque queremos usar esta clase desde código nativo y no se pueden usar tipos administrados en código nativo. Esta clase se compilará para tener como destino CLR, como indica la #pragma managed directiva anterior a la declaración de clase. Para obtener más información sobre esta directiva, vea managed, unmanaged.
Tenga en cuenta el miembro privado de la clase DatabaseClass: gcroot<DataTable ^> table . Puesto que los tipos nativos no pueden contener tipos administrados, gcroot la palabra clave es necesaria. Para obtener más información sobre gcroot , gcroot
El resto del código de este ejemplo es código nativo de C++, como se indica en la #pragma unmanaged directiva anterior main a . En este ejemplo, vamos a crear una nueva instancia de DatabaseClass y llamar a sus métodos para crear una tabla y rellenar algunas filas de la tabla. Tenga en cuenta que SAFEARRAY los tipos nativos se pasan como valores para la columna de base de datos ArrayIntsCol. Dentro de DatabaseClass, estos tipos se serializan en objetos administrados mediante la funcionalidad de serialización que se encuentra en el espacio de nombres SAFEARRAYSAFEARRAY En concreto, el método Copy se usa para serializar un objeto en una matriz administrada de enteros y el método Copy se usa para serializar una matriz administrada de enteros en .
// adonet_marshal_safearray.cpp
// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll
#include <comdef.h>
#include <gcroot.h>
#include <iostream>
using namespace std;
#using <System.Data.dll>
using namespace System;
using namespace System::Data;
using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managed
class DatabaseClass
{
public:
DatabaseClass() : table(nullptr) { }
void AddRow(SAFEARRAY *arrayIntsColValue)
{
// Add a row to the table.
DataRow ^row = table->NewRow();
int len = arrayIntsColValue->rgsabound[0].cElements;
array<int> ^arr = gcnew array<int>(len);
int *pData;
SafeArrayAccessData(arrayIntsColValue, (void **)&pData);
Marshal::Copy(IntPtr(pData), arr, 0, len);
SafeArrayUnaccessData(arrayIntsColValue);
row["ArrayIntsCol"] = arr;
table->Rows->Add(row);
}
void CreateAndPopulateTable()
{
// Create a simple DataTable.
table = gcnew DataTable("SampleTable");
// Add a column of type String to the table.
DataColumn ^column1 = gcnew DataColumn("ArrayIntsCol",
Type::GetType("System.Int32[]"));
table->Columns->Add(column1);
}
int GetValuesForColumn(wchar_t *dataColumn, SAFEARRAY **values,
int valuesLength)
{
// Marshal the name of the column to a managed
// String.
String ^columnStr = Marshal::PtrToStringUni(
(IntPtr)dataColumn);
// Get all rows in the table.
array<DataRow ^> ^rows = table->Select();
int len = rows->Length;
len = (len > valuesLength) ? valuesLength : len;
for (int i = 0; i < len; i++)
{
// Marshal each column value from a managed array
// of Int32s to a SAFEARRAY of type VT_I4.
values[i] = SafeArrayCreateVector(VT_I4, 0, 10);
int *pData;
SafeArrayAccessData(values[i], (void **)&pData);
Marshal::Copy((array<int> ^)rows[i][columnStr], 0,
IntPtr(pData), 10);
SafeArrayUnaccessData(values[i]);
}
return len;
}
private:
// Using gcroot, you can use a managed type in
// a native class.
gcroot<DataTable ^> table;
};
#pragma unmanaged
int main()
{
// Create a table and add a few rows to it.
DatabaseClass *db = new DatabaseClass();
db->CreateAndPopulateTable();
// Create a standard array.
int originalArray[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// Create a SAFEARRAY.
SAFEARRAY *psa;
psa = SafeArrayCreateVector(VT_I4, 0, 10);
// Copy the data from the original array to the SAFEARRAY.
int *pData;
HRESULT hr = SafeArrayAccessData(psa, (void **)&pData);
memcpy(pData, &originalArray, 40);
SafeArrayUnaccessData(psa);
db->AddRow(psa);
// Now retrieve the rows and display their contents.
SAFEARRAY *values[MAXCOLS];
int len = db->GetValuesForColumn(
L"ArrayIntsCol", values, MAXCOLS);
for (int i = 0; i < len; i++)
{
int *pData;
SafeArrayAccessData(values[i], (void **)&pData);
for (int j = 0; j < 10; j++)
{
cout << pData[j] << " ";
}
cout << endl;
SafeArrayUnaccessData(values[i]);
// Deallocate the memory allocated using
// SafeArrayCreateVector.
SafeArrayDestroy(values[i]);
}
SafeArrayDestroy(psa);
delete db;
return 0;
}
0 1 2 3 4 5 6 7 8 9
Compilar el código
Para compilar el código desde la línea de comandos, guarde el ejemplo de código en un archivo denominado adonet_marshal_safearray.cpp y escriba la siguiente instrucción:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_safearray.cpp
Seguridad de .NET Framework
Para obtener información sobre los problemas de seguridad relacionados con ADO.NET, vea Securing ADO.NET Applications.
Secciones relacionadas
| Sección | Descripción |
|---|---|
| ADO.NET | Proporciona información general sobre ADO.NET, un conjunto de clases que exponen los servicios de acceso a datos al programador de .NET. |
Vea también
Programación de .NET con C++/CLI (Visual C++)
Interoperabilidad nativa y .NET