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.

Microsoft ADO.NET Driver for Fabric Data Engineering le permite conectar, consultar y administrar cargas de trabajo de Spark en Microsoft Fabric con la confiabilidad y simplicidad de los patrones ADO.NET estándar. Basado en las API livy de Microsoft Fabric, el controlador proporciona conectividad de Spark SQL segura y flexible a las aplicaciones de .NET mediante abstracciones conocidas DbConnection, DbCommandy DbDataReader .

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, la ejecución SHOW SCHEMAS o SHOW DATABASES en un cuaderno de Fabric devuelve el mismo resultado: una lista de todos los esquemas de Lakehouse.

Prerrequisitos

Antes de usar Microsoft ADO.NET Driver for Microsoft Fabric Data Engineering, asegúrese de que tiene:

  • Runtime de .NET: .NET 8.0 o posterior
  • Microsoft Fabric Access: acceso a un área de trabajo de Microsoft Fabric con funcionalidades 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

Microsoft ADO.NET Driver for Microsoft Fabric Data Engineering versión 1.0.0 está en versión preliminar pública que puede descargar desde estos vínculos 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 Punto de conexión de la API de Microsoft Fabric https://api.fabric.microsoft.com/v1
SparkServerType Identificador de tipo de servidor Fabric
FabricWorkspaceID Identificador del área de trabajo de Microsoft Fabric (GUID) <workspace-id>
FabricLakehouseID Identificador de Lakehouse (GUID) de Microsoft Fabric <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
ARRAY<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

En esta sección se proporcionan instrucciones para resolver problemas comunes que pueden surgir al usar Microsoft ADO.NET Driver for Microsoft 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 Microsoft 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