Controlador de Microsoft ADO.NET para ingeniería de datos de Microsoft Fabric (versión preliminar)

Importante

Esta característica se encuentra en versión preliminar.

ADO.NET es una tecnología de acceso a datos ampliamente adoptada en el ecosistema de .NET que permite a las aplicaciones conectarse y trabajar con datos de bases de datos y plataformas de macrodatos.

El controlador Microsoft ADO.NET para Fabric Data Engineering te permite conectar, consultar y gestionar cargas de trabajo Spark en Fabric con la fiabilidad y simplicidad de los patrones estándar de ADO.NET. Construido sobre las APIs Livy de Fabric, el controlador proporciona conectividad SQL Spark segura y flexible a tus aplicaciones .NET utilizando las abstracciones familiares DbConnection, DbCommand, y DbDataReader abstracción.

Características clave

  • ADO.NET Compatible: implementación completa de abstracciones de ADO.NET (DbConnection, DbCommand, DbDataReader, DbParameter, DbProviderFactory)
  • Autenticación de Microsoft Entra ID: varios flujos de autenticación, como la CLI de Azure, el explorador interactivo, las credenciales de cliente, la autenticación basada en certificados y el token de acceso
  • Compatibilidad con consultas nativas de Spark SQL: ejecución directa de instrucciones SQL de Spark con consultas con parámetros
  • Compatibilidad completa con tipos de datos: compatibilidad con todos los tipos de datos de Spark SQL, incluidos tipos complejos (ARRAY, MAP, STRUCT)
  • Agrupación de conexiones: administración integrada de grupos de conexiones para mejorar el rendimiento
  • Reutilización de sesión: administración eficaz de sesiones de Spark para reducir la latencia de inicio
  • Captura previa asincrónica: carga de datos en segundo plano para mejorar el rendimiento con grandes conjuntos de resultados
  • Reconexión automática: recuperación automática de sesión después de errores de conexión

Nota:

En Apache Spark de código abierto, la base de datos y el esquema se usan como sinónimos. Por ejemplo, ejecutar SHOW SCHEMAS o SHOW DATABASES estar en un cuaderno Fabric devuelve el mismo resultado: una lista de todos los esquemas en la casa del lago.

Prerrequisitos

Antes de utilizar el controlador Microsoft ADO.NET para Fabric Data Engineering, asegúrate de que tienes:

  • Runtime de .NET: .NET 8.0 o posterior
  • Fabric Access: Acceso a un espacio de trabajo de Fabric con capacidades de Ingeniería de Datos
  • Credenciales de id. de Azure Entra: credenciales adecuadas para la autenticación
  • Identificadores de área de trabajo y Lakehouse: identificadores GUID para tu área de trabajo de Fabric y Lakehouse
  • CLI de Azure (opcional): necesario para el método de autenticación de la CLI de Azure

Descarga, inclusión, referencia y comprobación

Descarga del paquete NuGet

El controlador Microsoft ADO.NET para Fabric Data Engineering versión 1.0.0 está en una vista previa pública que puedes descargar desde estos enlaces del centro de descarga.

Hacer referencia al paquete NuGet en el proyecto

Incluya el paquete NuGet descargado en el proyecto y agregue una referencia del paquete al archivo del proyecto:

<ItemGroup>
    <PackageReference Include="Microsoft.Spark.Livy.AdoNet" Version="1.0.0" />
</ItemGroup>

Comprobación de la instalación

Después de incluir y hacer referencia, compruebe que el paquete está disponible en el proyecto:

using Microsoft.Spark.Livy.AdoNet;

// Verify the provider is registered
var factory = LivyProviderFactory.Instance;
Console.WriteLine($"Provider: {factory.GetType().Name}");

Ejemplo de inicio rápido

using Microsoft.Spark.Livy.AdoNet;

// Connection string with required parameters
string connectionString =
    "Server=https://api.fabric.microsoft.com/v1;" +
    "SparkServerType=Fabric;" +
    "FabricWorkspaceID=<workspace-id>;" +
    "FabricLakehouseID=<lakehouse-id>;" +
    "AuthFlow=AzureCli;";

// Create and open connection
using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();

Console.WriteLine("Connected successfully!");

// Execute a query
using var command = connection.CreateCommand();
command.CommandText = "SELECT 'Hello from Fabric!' as message";

using var reader = await command.ExecuteReaderAsync();
if (await reader.ReadAsync())
{
    Console.WriteLine(reader.GetString(0));
}

Formato de la cadena de conexión

Formato básico

Microsoft ADO.NET Driver usa el formato estándar de cadena de conexión ADO.NET:

Parameter1=Value1;Parameter2=Value2;...

Parámetros necesarios

Parámetro Descripción Ejemplo
Server Endpoint de la API de Fabric https://api.fabric.microsoft.com/v1
SparkServerType Identificador de tipo de servidor Fabric
FabricWorkspaceID Identificador de espacio de trabajo Fabric (GUID) <workspace-id>
FabricLakehouseID Identificador Fabric de la casa del lago (GUID) <lakehouse-id>
AuthFlow Método de autenticación AzureCli, BrowserBased, ClientSecretCredential, ClientCertificateCredential, , AuthAccessToken, FileToken

Parámetros opcionales

Configuración de conexión

Parámetro Tipo Predeterminado Descripción
LivySessionTimeoutSeconds Número entero 60 Tiempo en segundos para esperar a la creación de la sesión
LivyStatementTimeoutSeconds Número entero 600 Tiempo en segundos para esperar la ejecución de instrucciones
SessionName String (automático) Nombre personalizado para la sesión de Spark
AutoReconnect Boolean false Habilitación de la recuperación automática de sesión

Configuración del grupo de conexiones

Parámetro Tipo Predeterminado Descripción
ConnectionPoolEnabled Boolean true Habilitación de la agrupación de conexiones
MinPoolSize Número entero 1 Conexiones mínimas en el pool
MaxPoolSize Número entero 20 Número máximo de conexiones en el grupo
ConnectionMaxIdleTimeMs Número entero 1800000 Tiempo de inactividad máximo antes de reciclar la conexión (30 minutos)
MaxLifetimeMs Número entero 3600000 Duración máxima de una conexión agrupada (60 minutos)
ValidateConnections Boolean true Validación de conexiones antes de usar
ValidationTimeoutMs Número entero 5000 Tiempo de espera para la validación de la conexión

Configuración de registro

Parámetro Tipo Predeterminado Descripción
LogLevel String Information Nivel de registro: Trace, Debug, Information, Warning, Error
LogFilePath String (ninguno) Ruta de acceso para el registro basado en archivos

Nota:

Alias de controladores cruzados: El controlador acepta nombres de propiedad JDBC y ODBC además de nombres de ADO.NET nativos (por ejemplo, WorkspaceId se asigna a FabricWorkspaceID, LakehouseId se asigna a FabricLakehouseID). Todos los nombres de propiedad no distinguen mayúsculas de minúsculas.

Ejemplos de cadena de conexión

Conexión básica (autenticación de la CLI de Azure)

Server=https://api.fabric.microsoft.com/v1;SparkServerType=Fabric;FabricWorkspaceID=<workspace-id>;FabricLakehouseID=<lakehouse-id>;AuthFlow=AzureCli

Con opciones de agrupación de conexiones

Server=https://api.fabric.microsoft.com/v1;SparkServerType=Fabric;FabricWorkspaceID=<workspace-id>;FabricLakehouseID=<lakehouse-id>;AuthFlow=AzureCli;ConnectionPoolEnabled=true;MinPoolSize=2;MaxPoolSize=10

Con la reconexión automática y el registro

Server=https://api.fabric.microsoft.com/v1;SparkServerType=Fabric;FabricWorkspaceID=<workspace-id>;FabricLakehouseID=<lakehouse-id>;AuthFlow=AzureCli;AutoReconnect=true;LogLevel=Debug

Autenticación

Microsoft ADO.NET Driver admite varios métodos de autenticación a través de Microsoft Entra ID (anteriormente Azure Active Directory). La autenticación se configura mediante el AuthFlow parámetro en la cadena de conexión.

Métodos de autenticación

Valor de AuthFlow Descripción Mejor para
AzureCli Uso de credenciales almacenadas en caché de la CLI de Azure Desarrollo y pruebas
BrowserBased Autenticación interactiva basada en explorador Aplicaciones orientadas al usuario
ClientSecretCredential Entidad de servicio con secreto de cliente Servicios automatizados, trabajos en segundo plano
ClientCertificateCredential Entidad de servicio con certificado Aplicaciones empresariales
AuthAccessToken Token de acceso de portador adquirido previamente Escenarios de autenticación personalizados

Autenticación de la CLI de Azure

Mejor para: Desarrollo y pruebas

string connectionString =
    "Server=https://api.fabric.microsoft.com/v1;" +
    "SparkServerType=Fabric;" +
    "FabricWorkspaceID=<workspace-id>;" +
    "FabricLakehouseID=<lakehouse-id>;" +
    "AuthFlow=AzureCli;";

using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();

Requisitos previos:

  • CLI de Azure instalada: az --version
  • Iniciado sesión: az login

Autenticación interactiva del explorador

Mejor para: aplicaciones orientadas al usuario

string connectionString =
    "Server=https://api.fabric.microsoft.com/v1;" +
    "SparkServerType=Fabric;" +
    "FabricWorkspaceID=<workspace-id>;" +
    "FabricLakehouseID=<lakehouse-id>;" +
    "AuthFlow=BrowserBased;" +
    "AuthTenantID=<tenant-id>;";

using var connection = new LivyConnection(connectionString);
await connection.OpenAsync(); // Opens browser for authentication

Comportamiento:

  • Abre una ventana del explorador para la autenticación de usuario
  • Las credenciales se almacenan en caché para las conexiones posteriores

Autenticación de credenciales de cliente (principal de servicio)

Mejor para: Servicios automatizados y trabajos en segundo plano

string connectionString =
    "Server=https://api.fabric.microsoft.com/v1;" +
    "SparkServerType=Fabric;" +
    "FabricWorkspaceID=<workspace-id>;" +
    "FabricLakehouseID=<lakehouse-id>;" +
    "AuthFlow=ClientSecretCredential;" +
    "AuthTenantID=<tenant-id>;" +
    "AuthClientID=<client-id>;" +
    "AuthClientSecret=<client-secret>;";

using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();

Parámetros necesarios:

  • AuthTenantID: identificador de inquilino de Azure
  • AuthClientID: ID de aplicación (cliente) de Microsoft Entra ID
  • AuthClientSecret: secreto de cliente de Microsoft Entra ID

Autenticación basada en certificados

Mejor para: Aplicaciones empresariales que requieren autenticación basada en certificados

string connectionString =
    "Server=https://api.fabric.microsoft.com/v1;" +
    "SparkServerType=Fabric;" +
    "FabricWorkspaceID=<workspace-id>;" +
    "FabricLakehouseID=<lakehouse-id>;" +
    "AuthFlow=ClientCertificateCredential;" +
    "AuthTenantID=<tenant-id>;" +
    "AuthClientID=<client-id>;" +
    "AuthCertificatePath=C:\\certs\\mycert.pfx;" +
    "AuthCertificatePassword=<password>;";

using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();

Parámetros necesarios:

  • AuthTenantID: identificador de inquilino de Azure
  • AuthClientID: ID de aplicación (cliente)
  • AuthCertificatePath: ruta de acceso al archivo de certificado PFX/PKCS12
  • AuthCertificatePassword: contraseña de certificado

Autenticación de token de acceso

Mejor para: Escenarios de autenticación personalizados

// Acquire token through your custom mechanism
string accessToken = await AcquireTokenFromCustomSourceAsync();

string connectionString =
    "Server=https://api.fabric.microsoft.com/v1;" +
    "SparkServerType=Fabric;" +
    "FabricWorkspaceID=<workspace-id>;" +
    "FabricLakehouseID=<lakehouse-id>;" +
    "AuthFlow=AuthAccessToken;" +
    $"AuthAccessToken={accessToken};";

using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();

Nota:

Se recomienda encarecidamente evitar credenciales de codificación rígida, como contraseñas, claves, secretos, tokens o certificados en el código. En su lugar, use Azure Key Vault para almacenar estos valores de forma segura y recuperarlos en tiempo de ejecución.

Ejemplos de uso

Conexión básica y consulta

using Microsoft.Spark.Livy.AdoNet;

string connectionString =
    "Server=https://api.fabric.microsoft.com/v1;" +
    "SparkServerType=Fabric;" +
    "FabricWorkspaceID=<workspace-id>;" +
    "FabricLakehouseID=<lakehouse-id>;" +
    "AuthFlow=AzureCli;";

using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();

Console.WriteLine($"Connected! Server version: {connection.ServerVersion}");

// Execute a query
using var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM employees LIMIT 10";

using var reader = await command.ExecuteReaderAsync();

// Print column names
for (int i = 0; i < reader.FieldCount; i++)
{
    Console.Write($"{reader.GetName(i)}\t");
}
Console.WriteLine();

// Print rows
while (await reader.ReadAsync())
{
    for (int i = 0; i < reader.FieldCount; i++)
    {
        Console.Write($"{reader.GetValue(i)}\t");
    }
    Console.WriteLine();
}

Consultas parametrizadas

using var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM orders WHERE order_date >= @startDate AND status = @status";

// Add parameters
command.Parameters.AddWithValue("@startDate", new DateTime(2024, 1, 1));
command.Parameters.AddWithValue("@status", "completed");

using var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
    Console.WriteLine($"Order: {reader["order_id"]}, Total: {reader["total"]:C}");
}

ExecuteScalar para valores únicos

using var command = connection.CreateCommand();
command.CommandText = "SELECT COUNT(*) FROM customers";

var count = await command.ExecuteScalarAsync();
Console.WriteLine($"Total customers: {count}");

ExecuteNonQuery para operaciones DML

// INSERT
using var insertCommand = connection.CreateCommand();
insertCommand.CommandText = @"
    INSERT INTO employees (id, name, department, salary)
    VALUES (100, 'John Doe', 'Engineering', 85000)";

int rowsAffected = await insertCommand.ExecuteNonQueryAsync();
Console.WriteLine($"Inserted {rowsAffected} row(s)");

// UPDATE
using var updateCommand = connection.CreateCommand();
updateCommand.CommandText = "UPDATE employees SET salary = 90000 WHERE id = 100";

rowsAffected = await updateCommand.ExecuteNonQueryAsync();
Console.WriteLine($"Updated {rowsAffected} row(s)");

// DELETE
using var deleteCommand = connection.CreateCommand();
deleteCommand.CommandText = "DELETE FROM employees WHERE id = 100";

rowsAffected = await deleteCommand.ExecuteNonQueryAsync();
Console.WriteLine($"Deleted {rowsAffected} row(s)");

Trabajar con grandes conjuntos de resultados

using var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM large_table";

using var reader = await command.ExecuteReaderAsync();

int rowCount = 0;
while (await reader.ReadAsync())
{
    // Process each row
    ProcessRow(reader);
    rowCount++;

    if (rowCount % 10000 == 0)
    {
        Console.WriteLine($"Processed {rowCount} rows...");
    }
}

Console.WriteLine($"Total rows processed: {rowCount}");

Detección de esquemas

// List all tables
using var showTablesCommand = connection.CreateCommand();
showTablesCommand.CommandText = "SHOW TABLES";

using var tablesReader = await showTablesCommand.ExecuteReaderAsync();
Console.WriteLine("Available tables:");
while (await tablesReader.ReadAsync())
{
    Console.WriteLine($"  {tablesReader.GetString(0)}");
}

// Describe table structure
using var describeCommand = connection.CreateCommand();
describeCommand.CommandText = "DESCRIBE employees";

using var schemaReader = await describeCommand.ExecuteReaderAsync();
Console.WriteLine("\nTable structure for 'employees':");
while (await schemaReader.ReadAsync())
{
    Console.WriteLine($"  {schemaReader["col_name"]}: {schemaReader["data_type"]}");
}

Uso de LivyConnectionStringBuilder

using Microsoft.Spark.Livy.AdoNet;

var builder = new LivyConnectionStringBuilder
{
    Server = "https://api.fabric.microsoft.com/v1",
    SparkServerType = "Fabric",
    FabricWorkspaceID = "<workspace-id>",
    FabricLakehouseID = "<lakehouse-id>",
    AuthFlow = "AzureCli",
    ConnectionPoolingEnabled = true,
    MinPoolSize = 2,
    MaxPoolSize = 10,
    ConnectionTimeout = 60
};

using var connection = new LivyConnection(builder.ConnectionString);
await connection.OpenAsync();

Uso de DbProviderFactory

using System.Data.Common;
using Microsoft.Spark.Livy.AdoNet;

// Register the provider factory (typically done at application startup)
DbProviderFactories.RegisterFactory("Microsoft.Spark.Livy.AdoNet", LivyProviderFactory.Instance);

// Create connection using factory
var factory = DbProviderFactories.GetFactory("Microsoft.Spark.Livy.AdoNet");

using var connection = factory.CreateConnection();
connection.ConnectionString = connectionString;

await connection.OpenAsync();

using var command = factory.CreateCommand();
command.Connection = connection;
command.CommandText = "SELECT * FROM employees LIMIT 5";

using var reader = await command.ExecuteReaderAsync();
// Process results...

Asignación de tipos de datos

El controlador asigna los tipos de datos de Spark SQL a tipos de .NET:

Tipo de SQL de Spark Tipo de .NET DbType
BOOLEAN bool Boolean
TINYINT sbyte SByte
SMALLINT short Int16
INT int Int32
BIGINT long Int64
FLOTAR float Soltero
DOUBLE double Double
DECIMAL(p,s) decimal Decimal
STRING string String
VARCHAR(n) string String
CHAR(n) string String
BINARIO byte[] Binary
FECHA DateTime Fecha
TIMESTAMP DateTime DateTime
MATRIZ<T> T[] o string (JSON) Objeto
MAP<K,V> Dictionary<K,V> o string (JSON) Objeto
ESTRUCTURA object o string (JSON) Objeto

Trabajar con tipos complejos

Los tipos complejos (ARRAY, MAP, STRUCT) se devuelven como cadenas JSON de forma predeterminada:

using System.Text.Json;
using System.Collections.Generic;

using var command = connection.CreateCommand();
command.CommandText = "SELECT array_column, map_column, struct_column FROM complex_table LIMIT 1";

using var reader = await command.ExecuteReaderAsync();
if (await reader.ReadAsync())
{
    // Complex types returned as JSON strings
    string arrayJson = reader.GetString(0);  // e.g., "[1, 2, 3]"
    string mapJson = reader.GetString(1);    // e.g., "{\"key\": \"value\"}"
    string structJson = reader.GetString(2); // e.g., "{\"field1\": 1, \"field2\": \"text\"}"

    // Parse with System.Text.Json
    var array = JsonSerializer.Deserialize<int[]>(arrayJson);
    var map = JsonSerializer.Deserialize<Dictionary<string, string>>(mapJson);
}

Solución de problemas

Esta sección ofrece orientación para resolver problemas comunes que puedas encontrar al usar el controlador Microsoft ADO.NET para Fabric Data Engineering.

Problemas comunes

En las secciones siguientes se describen problemas comunes y sus soluciones:

Fallos de conexión

Problema: No se puede conectar a Fabric

Soluciones:

  1. Verifique que FabricWorkspaceID y FabricLakehouseID sean GUID correctos
  2. Compruebe la autenticación de la CLI de Azure: az account show
  3. Asegúrese de que tiene los permisos adecuados del área de trabajo de Fabric.
  4. Comprobación de la conectividad de red a api.fabric.microsoft.com

Errores de autenticación

Problema: error de autenticación con la CLI de Azure

Soluciones:

  • Ejecución az login para actualizar las credenciales
  • Compruebe el inquilino correcto: az account set --subscription <subscription-id>
  • Comprobar la validez del token: az account get-access-token --resource https://api.fabric.microsoft.com

Tiempos de espera de consulta agotados

Problema: Las consultas agotan el tiempo de espera en tablas grandes

Soluciones:

  • Incrementar el tiempo de espera de la instrucción: LivyStatementTimeoutSeconds=300
  • Use la cláusula LIMIT para restringir el tamaño del resultado durante el desarrollo.
  • Asegúrese de que el clúster de Spark tiene recursos adecuados

Tiempo de espera de creación de la sesión

Problema: El tiempo de espera de la conexión se agota durante la creación de la sesión

Soluciones:

  • Aumentar el tiempo de espera de la sesión: LivySessionTimeoutSeconds=120
  • Comprobación de la disponibilidad de la capacidad de Fabric
  • Verificar que el área de trabajo no haya alcanzado los límites de sesión

Habilitar registro

Al solucionar problemas, habilitar el registro detallado puede ayudarle a identificar la causa principal de los problemas. Puede habilitar el registro a través de la cadena de conexión o mediante programación.

Para habilitar el registro detallado a través de la cadena de conexión:

LogLevel=Debug

O bien, configure mediante programación:

using Microsoft.Extensions.Logging;

var loggerFactory = LoggerFactory.Create(builder =>
{
    builder.AddConsole();
    builder.SetMinimumLevel(LogLevel.Debug);
});

// Logging is automatically integrated with the connection

Niveles de registro:

  • Trace: La máxima verbosidad, incluye todas las llamadas a la API.
  • Debug: información detallada de depuración
  • Information: información general (valor predeterminado)
  • Warning: solo advertencias
  • Error: solo errores