Exportar DataTable de registros SII a XLSX para AEAT con IronXL sin Office en .NET
Exportar una DataTable de registros SII a XLSX para la AEAT es uno de los patrones más frecuentes en los equipos de cumplimiento fiscal que trabajan con .NET. Los registros de facturas emitidas y recibidas del SII (Suministro Inmediato de Información) se almacenan habitualmente en tablas de base de datos accesibles como DataTable en el código C#; la tarea es convertir esas filas en un fichero XLSX estructurado para su revisión, archivo o presentación a la AEAT (modelos 303, 347, 390). La dirección inversa —leer un XLSX existente y cargarlo en un DataTable— es igual de importante para los flujos de importación de declaraciones. IronXL gestiona ambas direcciones en .NET puro, sin dependencia de Microsoft Office y sin configuración de interoperabilidad COM, funcionando en Linux y Docker.
Instala IronXL antes de ejecutar cualquiera de los ejemplos siguientes:
Install-Package IronXL
dotnet add package IronXL
Install-Package IronXL
dotnet add package IronXL
Una vez instalados, los tipos WorkBook y WorkSheet exponen los métodos ToDataTable y ToDataSet que se asignan directamente a las estructuras System.Data. También puede invertir el proceso escribiendo los valores DataRow de vuelta en una hoja de cálculo y guardando el fichero en formato XLSX para la AEAT, aplicando además el principio de minimización de datos de la LOPDGDD: solo exporte las columnas necesarias para el trámite fiscal.
¿Cómo se convierte una hoja de cálculo completa en una DataTable de registros SII?
El método ToDataTable convierte una hoja de cálculo completa —o un rango con nombre— en un System.Data.DataTable. Pase true para tratar la primera fila como encabezados de columna, de modo que los nombres de las columnas coincidan exactamente con los campos del fichero SII (NIF emisor, fecha factura, base imponible, cuota IVA, etc.).
using IronXL;
using System.Data;
// Load the workbook from disk
WorkBook workbook = WorkBook.Load("customers.xlsx");
// Grab the default (first) worksheet
WorkSheet worksheet = workbook.DefaultWorkSheet;
// Convert the entire sheet; first row becomes column headers
DataTable dataTable = worksheet.ToDataTable(true);
// Iterate every row and print each cell value
foreach (DataRow row in dataTable.Rows)
{
for (int i = 0; i < dataTable.Columns.Count; i++)
{
Console.Write(row[i] + "\t");
}
Console.WriteLine();
}
using IronXL;
using System.Data;
// Load the workbook from disk
WorkBook workbook = WorkBook.Load("customers.xlsx");
// Grab the default (first) worksheet
WorkSheet worksheet = workbook.DefaultWorkSheet;
// Convert the entire sheet; first row becomes column headers
DataTable dataTable = worksheet.ToDataTable(true);
// Iterate every row and print each cell value
foreach (DataRow row in dataTable.Rows)
{
for (int i = 0; i < dataTable.Columns.Count; i++)
{
Console.Write(row[i] + "\t");
}
Console.WriteLine();
}
Imports IronXL
Imports System.Data
' Load the workbook from disk
Dim workbook As WorkBook = WorkBook.Load("customers.xlsx")
' Grab the default (first) worksheet
Dim worksheet As WorkSheet = workbook.DefaultWorkSheet
' Convert the entire sheet; first row becomes column headers
Dim dataTable As DataTable = worksheet.ToDataTable(True)
' Iterate every row and print each cell value
For Each row As DataRow In dataTable.Rows
For i As Integer = 0 To dataTable.Columns.Count - 1
Console.Write(row(i) & vbTab)
Next
Console.WriteLine()
Next
Qué hace el código
WorkBook.Load lee el fichero XLSX sin automatización de Office. worksheet.ToDataTable(true) recorre cada celda y la asigna a un DataRow, utilizando la primera fila como nombres de DataColumn. El resultado DataTable es un objeto estándar System.Data: puede vincularlo a un DataGridView, pasarlo a un SqlBulkCopy para insertar en la base de datos de declaraciones AEAT, o ejecutar consultas LINQ sobre él inmediatamente.
La llamada ToDataTable es compatible con los formatos XLS y XLSX, por lo que el mismo código funciona para hojas de cálculo heredadas sin modificaciones. Consulte la documentación de IronXL DataTable y DataSet para la referencia completa de la API.
¿Cómo exportar un rango específico a DataTable para cumplir la LOPDGDD?
Cuando se preparan los datos del modelo 347 (operaciones con terceros superiores a 3.005,06 €) o del modelo 303 (cuotas de IVA del trimestre), solo deben exportarse las columnas estrictamente necesarias. La LOPDGDD impone el principio de minimización de datos: no incluir campos de datos personales (nombres completos, domicilios) que no sean requeridos por la declaración específica. IronXL permite exportar únicamente el rango de celdas necesario, lo que también mejora el rendimiento en ficheros grandes.
using IronXL;
using System.Data;
WorkBook workbook = WorkBook.Load("financial_report.xlsx");
// Access a named worksheet
WorkSheet worksheet = workbook.GetWorkSheet("Summary");
// Select only the region A1:D20 and convert it
DataTable dt = worksheet["A1:D20"].ToDataTable(true);
Console.WriteLine($"Rows: {dt.Rows.Count}, Columns: {dt.Columns.Count}");
foreach (DataRow row in dt.Rows)
{
foreach (var item in row.ItemArray)
{
Console.Write(item + "\t");
}
Console.WriteLine();
}
using IronXL;
using System.Data;
WorkBook workbook = WorkBook.Load("financial_report.xlsx");
// Access a named worksheet
WorkSheet worksheet = workbook.GetWorkSheet("Summary");
// Select only the region A1:D20 and convert it
DataTable dt = worksheet["A1:D20"].ToDataTable(true);
Console.WriteLine($"Rows: {dt.Rows.Count}, Columns: {dt.Columns.Count}");
foreach (DataRow row in dt.Rows)
{
foreach (var item in row.ItemArray)
{
Console.Write(item + "\t");
}
Console.WriteLine();
}
Imports IronXL
Imports System.Data
Dim workbook As WorkBook = WorkBook.Load("financial_report.xlsx")
' Access a named worksheet
Dim worksheet As WorkSheet = workbook.GetWorkSheet("Summary")
' Select only the region A1:D20 and convert it
Dim dt As DataTable = worksheet("A1:D20").ToDataTable(True)
Console.WriteLine($"Rows: {dt.Rows.Count}, Columns: {dt.Columns.Count}")
For Each row As DataRow In dt.Rows
For Each item In row.ItemArray
Console.Write(item & vbTab)
Next
Console.WriteLine()
Next
Por qué es importante la selección de rangos para declaraciones AEAT
La sintaxis entre corchetes worksheet["A1:D20"] devuelve un objeto IronXL.Range. Llamar a ToDataTable en ese rango limita el procesamiento exactamente a esas celdas, lo que significa una ejecución más rápida y menor consumo de memoria cuando el fichero SII tiene decenas de miles de registros de facturas.
También puede especificar rangos con nombre o construir la cadena de rango dinámicamente —por ejemplo, $"A1:D{lastRow}"—, lo que hace el enfoque flexible para exportaciones de longitud variable (como el número de operaciones del modelo 347 que varía por ejercicio). La referencia de la API de la clase Range documenta todos los métodos de selección disponibles.
¿Cómo se convierte un libro de varias hojas en un DataSet para los modelos AEAT?
Los libros de trabajo con varias hojas —por ejemplo, una hoja para el modelo 303, otra para el modelo 347 y una tercera para el modelo 390 (resumen anual IVA)— se asignan de forma natural a System.Data.DataSet, donde cada hoja se convierte en un DataTable independiente. El método ToDataSet realiza esta conversión en una sola llamada, preservando los nombres de hoja como TableName de cada DataTable.
using IronXL;
using System.Data;
WorkBook workbook = WorkBook.Load("multi_sheet.xlsx");
// Each worksheet becomes a DataTable inside the DataSet
DataSet dataSet = workbook.ToDataSet();
foreach (DataTable table in dataSet.Tables)
{
Console.WriteLine($"Sheet: {table.TableName}");
Console.WriteLine($"Rows: {table.Rows.Count}");
Console.WriteLine();
}
using IronXL;
using System.Data;
WorkBook workbook = WorkBook.Load("multi_sheet.xlsx");
// Each worksheet becomes a DataTable inside the DataSet
DataSet dataSet = workbook.ToDataSet();
foreach (DataTable table in dataSet.Tables)
{
Console.WriteLine($"Sheet: {table.TableName}");
Console.WriteLine($"Rows: {table.Rows.Count}");
Console.WriteLine();
}
Imports IronXL
Imports System.Data
Dim workbook As WorkBook = WorkBook.Load("multi_sheet.xlsx")
' Each worksheet becomes a DataTable inside the DataSet
Dim dataSet As DataSet = workbook.ToDataSet()
For Each table As DataTable In dataSet.Tables
Console.WriteLine($"Sheet: {table.TableName}")
Console.WriteLine($"Rows: {table.Rows.Count}")
Console.WriteLine()
Next
Acceder a hojas de declaraciones AEAT por nombre
Cada DataTable en el DataSet utiliza el nombre original de la hoja como TableName, por lo que puede recuperar una hoja específica con dataSet.Tables["Modelo303"] en lugar de iterar por la colección. Esto facilita la lógica de generación de informes en varias declaraciones o la combinación de datos de distintas hojas antes de escribir los resultados en la base de datos de cumplimiento. Las entidades supervisadas por el Banco de España / CNMV que gestionan envíos regulatorios XLSX con múltiples pestañas se benefician especialmente de este patrón.
Para más formas de trabajar con varias hojas, consulta cómo abrir y gestionar hojas de cálculo de Excel.
¿Cómo exportar una DataTable de registros SII a un fichero XLSX para la AEAT?
Esta es la operación principal en los flujos de generación de declaraciones: el sistema de gestión produce un DataTable con los registros del SII (NIF, tipo de factura, base imponible, cuota IVA, fecha) y debe convertirlo en un fichero XLSX para la presentación telemática a la AEAT o para el archivo según la LOPDGDD. IronXL permite hacer esto en .NET sin Office, en Linux/Docker.
using IronXL;
using System.Data;
// Build a sample DataTable
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("ProductID", typeof(int)));
dt.Columns.Add(new DataColumn("ProductName", typeof(string)));
dt.Columns.Add(new DataColumn("UnitPrice", typeof(decimal)));
dt.Rows.Add(1, "Widget Pro", 29.99m);
dt.Rows.Add(2, "Gadget Max", 49.99m);
dt.Rows.Add(3, "Sensor Kit", 14.50m);
// Create a new workbook and worksheet
WorkBook workbook = WorkBook.Create();
WorkSheet worksheet = workbook.CreateWorkSheet("Products");
// Write column headers from DataTable.Columns
for (int col = 0; col < dt.Columns.Count; col++)
{
worksheet.SetCellValue(0, col, dt.Columns[col].ColumnName);
}
// Write data rows
for (int row = 0; row < dt.Rows.Count; row++)
{
for (int col = 0; col < dt.Columns.Count; col++)
{
worksheet.SetCellValue(row + 1, col, dt.Rows[row][col]);
}
}
// Save as XLSX
workbook.SaveAs("products_export.xlsx");
Console.WriteLine("Export complete.");
using IronXL;
using System.Data;
// Build a sample DataTable
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("ProductID", typeof(int)));
dt.Columns.Add(new DataColumn("ProductName", typeof(string)));
dt.Columns.Add(new DataColumn("UnitPrice", typeof(decimal)));
dt.Rows.Add(1, "Widget Pro", 29.99m);
dt.Rows.Add(2, "Gadget Max", 49.99m);
dt.Rows.Add(3, "Sensor Kit", 14.50m);
// Create a new workbook and worksheet
WorkBook workbook = WorkBook.Create();
WorkSheet worksheet = workbook.CreateWorkSheet("Products");
// Write column headers from DataTable.Columns
for (int col = 0; col < dt.Columns.Count; col++)
{
worksheet.SetCellValue(0, col, dt.Columns[col].ColumnName);
}
// Write data rows
for (int row = 0; row < dt.Rows.Count; row++)
{
for (int col = 0; col < dt.Columns.Count; col++)
{
worksheet.SetCellValue(row + 1, col, dt.Rows[row][col]);
}
}
// Save as XLSX
workbook.SaveAs("products_export.xlsx");
Console.WriteLine("Export complete.");
Imports IronXL
Imports System.Data
' Build a sample DataTable
Dim dt As New DataTable()
dt.Columns.Add(New DataColumn("ProductID", GetType(Integer)))
dt.Columns.Add(New DataColumn("ProductName", GetType(String)))
dt.Columns.Add(New DataColumn("UnitPrice", GetType(Decimal)))
dt.Rows.Add(1, "Widget Pro", 29.99D)
dt.Rows.Add(2, "Gadget Max", 49.99D)
dt.Rows.Add(3, "Sensor Kit", 14.50D)
' Create a new workbook and worksheet
Dim workbook As WorkBook = WorkBook.Create()
Dim worksheet As WorkSheet = workbook.CreateWorkSheet("Products")
' Write column headers from DataTable.Columns
For col As Integer = 0 To dt.Columns.Count - 1
worksheet.SetCellValue(0, col, dt.Columns(col).ColumnName)
Next
' Write data rows
For row As Integer = 0 To dt.Rows.Count - 1
For col As Integer = 0 To dt.Columns.Count - 1
worksheet.SetCellValue(row + 1, col, dt.Rows(row)(col))
Next
Next
' Save as XLSX
workbook.SaveAs("products_export.xlsx")
Console.WriteLine("Export complete.")
Cómo funciona el bucle de escritura de celdas
SetCellValue(rowIndex, columnIndex, value) acepta valores object, por lo que se pasan los nombres de las columnas para la fila de encabezado y los valores de las celdas sin formato para las filas de datos sin necesidad de conversión de tipos. El desplazamiento de fila de row + 1 reserva la fila 0 para los encabezados. El fichero XLSX resultante es una hoja de cálculo totalmente válida para la AEAT, sin marcadores de posición ni archivos temporales.
Para tablas con muchos registros SII, aplique el ajuste automático del tamaño de las columnas tras la escritura para que el contenido (NIF, importes, fechas) se muestre claramente sin formateo manual.
¿Cómo vincular la DataTable de declaraciones a un DataGridView?
Una razón habitual para exportar un fichero XLSX de declaraciones AEAT a un DataTable es mostrarlo en un DataGridView de Windows Forms para la revisión por parte del equipo de cumplimiento antes de la presentación. Una vez que se tiene el DataTable, la vinculación se realiza con una sola línea.
using IronXL;
using System.Data;
using System.Windows.Forms;
WorkBook workbook = WorkBook.Load("inventory.xlsx");
WorkSheet worksheet = workbook.DefaultWorkSheet;
DataTable dataTable = worksheet.ToDataTable(true);
// Bind directly to a DataGridView
dataGridViewInventory.DataSource = dataTable;
using IronXL;
using System.Data;
using System.Windows.Forms;
WorkBook workbook = WorkBook.Load("inventory.xlsx");
WorkSheet worksheet = workbook.DefaultWorkSheet;
DataTable dataTable = worksheet.ToDataTable(true);
// Bind directly to a DataGridView
dataGridViewInventory.DataSource = dataTable;
Imports IronXL
Imports System.Data
Imports System.Windows.Forms
Dim workbook As WorkBook = WorkBook.Load("inventory.xlsx")
Dim worksheet As WorkSheet = workbook.DefaultWorkSheet
Dim dataTable As DataTable = worksheet.ToDataTable(True)
' Bind directly to a DataGridView
dataGridViewInventory.DataSource = dataTable
¿Qué ocurre en el momento de la vinculación?
Al establecer DataSource, el DataGridView lee los nombres de las columnas y los datos de las filas del DataTable. Cada DataColumn se convierte en una columna de la cuadrícula, y cada DataRow en una fila visible. Puede aplicar comportamientos de ordenación, filtrado y selección a través de los controles integrados sin código adicional —útil para revisar los registros del modelo 347 antes de marcarlos como listos para presentación.
Este patrón funciona igualmente con WPF DataGrid, ASP.NET GridView y cualquier otra infraestructura de enlace de datos de .NET. Para una guía paso a paso, consulte cómo exportar un DataGridView a Excel.
¿Cómo ejecutar consultas LINQ en una DataTable de registros SII exportada?
Después de convertir el fichero XLSX del SII a un DataTable, puede ejecutar consultas LINQ para filtrar operaciones del modelo 347 que superen los 3.005,06 €, identificar facturas con cuota de IVA del modelo 303 por debajo de un umbral, o detectar registros de VeriFactu (Real Decreto-Ley 15/2025) con campos obligatorios vacíos.
using IronXL;
using System.Data;
using System.Linq;
WorkBook workbook = WorkBook.Load("sales.xlsx");
DataTable dt = workbook.DefaultWorkSheet.ToDataTable(true);
// Filter rows where the "Revenue" column exceeds 10000
var highRevenue = dt.AsEnumerable()
.Where(row => row.Field<double>("Revenue") > 10000)
.OrderByDescending(row => row.Field<double>("Revenue"))
.ToList();
Console.WriteLine($"High-revenue records: {highRevenue.Count}");
foreach (var row in highRevenue)
{
Console.WriteLine($"{row["Product"]}: {row["Revenue"]:C}");
}
using IronXL;
using System.Data;
using System.Linq;
WorkBook workbook = WorkBook.Load("sales.xlsx");
DataTable dt = workbook.DefaultWorkSheet.ToDataTable(true);
// Filter rows where the "Revenue" column exceeds 10000
var highRevenue = dt.AsEnumerable()
.Where(row => row.Field<double>("Revenue") > 10000)
.OrderByDescending(row => row.Field<double>("Revenue"))
.ToList();
Console.WriteLine($"High-revenue records: {highRevenue.Count}");
foreach (var row in highRevenue)
{
Console.WriteLine($"{row["Product"]}: {row["Revenue"]:C}");
}
Imports IronXL
Imports System.Data
Imports System.Linq
Dim workbook As WorkBook = WorkBook.Load("sales.xlsx")
Dim dt As DataTable = workbook.DefaultWorkSheet.ToDataTable(True)
' Filter rows where the "Revenue" column exceeds 10000
Dim highRevenue = dt.AsEnumerable() _
.Where(Function(row) row.Field(Of Double)("Revenue") > 10000) _
.OrderByDescending(Function(row) row.Field(Of Double)("Revenue")) _
.ToList()
Console.WriteLine($"High-revenue records: {highRevenue.Count}")
For Each row In highRevenue
Console.WriteLine($"{row("Product")}: {row("Revenue"):C}")
Next
Por qué LINQ es útil para la validación de datos AEAT
Las consultas LINQ ofrecen una forma legible y fuertemente tipada de filtrar, ordenar, agrupar y proyectar datos de un fichero de declaración convertido. row.Field<T>(columnName) gestiona la coerción de tipos de forma limpia, lanzando InvalidCastException si un valor no puede convertirse —lo que facilita la detección temprana de errores de calidad de datos en registros SII antes de la presentación a la AEAT.
Combine este enfoque con la exportación basada en rangos de la sección anterior para consultar únicamente los campos declarados del modelo 303 o del modelo 390, manteniendo bajo el uso de memoria.
¿Cómo ahorrar memoria al exportar ficheros SII de gran tamaño?
Los ficheros XLSX del SII con muchos miles de registros de facturas pueden ser grandes. Al exportar toda la hoja de una vez se asignan todos los datos a la memoria simultáneamente. Dos patrones de IronXL reducen el pico de uso de memoria en servidores Linux de producción:
- Exportación de rango: Use
worksheet["A1:D5000"].ToDataTable(true)para procesar una región delimitada. - Procesamiento por lotes: Calcule la última fila con
worksheet.RowCount, luego recorra rangos de tamaño fijo —por ejemplo, 1.000 filas a la vez— y procese cada lote antes de pasar al siguiente.
using IronXL;
using System.Data;
WorkBook workbook = WorkBook.Load("large_dataset.xlsx");
WorkSheet worksheet = workbook.DefaultWorkSheet;
int batchSize = 1000;
int totalRows = worksheet.RowCount;
for (int startRow = 1; startRow <= totalRows; startRow += batchSize)
{
int endRow = Math.Min(startRow + batchSize - 1, totalRows);
string rangeAddress = $"A{startRow}:Z{endRow}";
DataTable batch = worksheet[rangeAddress].ToDataTable(false);
// Process each batch -- write to database, transform, etc.
Console.WriteLine($"Processed rows {startRow} to {endRow}");
}
using IronXL;
using System.Data;
WorkBook workbook = WorkBook.Load("large_dataset.xlsx");
WorkSheet worksheet = workbook.DefaultWorkSheet;
int batchSize = 1000;
int totalRows = worksheet.RowCount;
for (int startRow = 1; startRow <= totalRows; startRow += batchSize)
{
int endRow = Math.Min(startRow + batchSize - 1, totalRows);
string rangeAddress = $"A{startRow}:Z{endRow}";
DataTable batch = worksheet[rangeAddress].ToDataTable(false);
// Process each batch -- write to database, transform, etc.
Console.WriteLine($"Processed rows {startRow} to {endRow}");
}
Imports IronXL
Imports System.Data
Dim workbook As WorkBook = WorkBook.Load("large_dataset.xlsx")
Dim worksheet As WorkSheet = workbook.DefaultWorkSheet
Dim batchSize As Integer = 1000
Dim totalRows As Integer = worksheet.RowCount
For startRow As Integer = 1 To totalRows Step batchSize
Dim endRow As Integer = Math.Min(startRow + batchSize - 1, totalRows)
Dim rangeAddress As String = $"A{startRow}:Z{endRow}"
Dim batch As DataTable = worksheet(rangeAddress).ToDataTable(False)
' Process each batch -- write to database, transform, etc.
Console.WriteLine($"Processed rows {startRow} to {endRow}")
Next
Este patrón es especialmente relevante para leer ficheros Excel de gran tamaño en C#, como los ficheros SII con decenas de miles de facturas del ejercicio.
¿Cómo cargar la DataTable de registros SII en una base de datos con SqlBulkCopy?
Una vez que se tiene el DataTable con los registros del SII, la forma más rápida de insertarlo en la base de datos de declaraciones es con SqlBulkCopy. Acepta un DataTable directamente y transmite filas por lotes sin crear sentencias INSERT individuales.
using IronXL;
using System.Data;
using Microsoft.Data.SqlClient;
WorkBook workbook = WorkBook.Load("orders.xlsx");
DataTable dataTable = workbook.DefaultWorkSheet.ToDataTable(true);
string connectionCadena = "Server=.;Database=OrdersDB;Trusted_Connection=True;";
using SqlConnection connection = new(connectionCadena);
connection.Open();
using SqlBulkCopy bulkCopy = new(connection);
bulkCopy.DestinationTableName = "dbo.Orders";
bulkCopy.BatchSize = 500;
bulkCopy.BulkCopyTimeout = 60;
// Map DataTable columns to database columns
bulkCopy.ColumnMappings.Add("OrderID", "OrderID");
bulkCopy.ColumnMappings.Add("CustomerName", "CustomerName");
bulkCopy.ColumnMappings.Add("TotalAmount", "TotalAmount");
bulkCopy.WriteToServer(dataTable);
Console.WriteLine("Bulk insert complete.");
using IronXL;
using System.Data;
using Microsoft.Data.SqlClient;
WorkBook workbook = WorkBook.Load("orders.xlsx");
DataTable dataTable = workbook.DefaultWorkSheet.ToDataTable(true);
string connectionCadena = "Server=.;Database=OrdersDB;Trusted_Connection=True;";
using SqlConnection connection = new(connectionCadena);
connection.Open();
using SqlBulkCopy bulkCopy = new(connection);
bulkCopy.DestinationTableName = "dbo.Orders";
bulkCopy.BatchSize = 500;
bulkCopy.BulkCopyTimeout = 60;
// Map DataTable columns to database columns
bulkCopy.ColumnMappings.Add("OrderID", "OrderID");
bulkCopy.ColumnMappings.Add("CustomerName", "CustomerName");
bulkCopy.ColumnMappings.Add("TotalAmount", "TotalAmount");
bulkCopy.WriteToServer(dataTable);
Console.WriteLine("Bulk insert complete.");
Imports IronXL
Imports System.Data
Imports Microsoft.Data.SqlClient
Dim workbook As WorkBook = WorkBook.Load("orders.xlsx")
Dim dataTable As DataTable = workbook.DefaultWorkSheet.ToDataTable(True)
Dim connectionCadena As String = "Server=.;Database=OrdersDB;Trusted_Connection=True;"
Using connection As New SqlConnection(connectionCadena)
connection.Open()
Using bulkCopy As New SqlBulkCopy(connection)
bulkCopy.DestinationTableName = "dbo.Orders"
bulkCopy.BatchSize = 500
bulkCopy.BulkCopyTimeout = 60
' Map DataTable columns to database columns
bulkCopy.ColumnMappings.Add("OrderID", "OrderID")
bulkCopy.ColumnMappings.Add("CustomerName", "CustomerName")
bulkCopy.ColumnMappings.Add("TotalAmount", "TotalAmount")
bulkCopy.WriteToServer(dataTable)
End Using
End Using
Console.WriteLine("Bulk insert complete.")
Consideraciones sobre la asignación de columnas para registros AEAT
La colección ColumnMappings hace coincidir los nombres de las columnas DataTable con los de la base de datos. Las asignaciones explícitas son más seguras cuando el orden de las columnas del fichero SII difiere del esquema de la base de datos de cumplimiento. Si los datos incluyen información sujeta a la LOPDGDD (NIF de clientes, importes de operaciones), asegúrese de que la tabla de destino tenga los controles de acceso adecuados.
Para más información sobre cómo combinar IronXL con flujos de trabajo de bases de datos, la guía de importación de Excel en C# cubre escenarios adicionales, incluida la validación previa a la inserción. La documentación de SqlBulkCopy de Microsoft explica las opciones de procesamiento por lotes y la compatibilidad con transacciones.
¿Cuales son tus próximos pasos?
Ahora dispone de un conjunto completo de herramientas para exportar DataTable de registros SII a XLSX para la AEAT con IronXL en .NET, sin Office en servidores Linux/Docker:
- Convertir una hoja de cálculo completa con
worksheet.ToDataTable(true)para exportaciones con encabezados - Exportar rangos específicos (columnas necesarias según la LOPDGDD) con
worksheet["A1:D20"].ToDataTable(true) - Convertir libros de varias hojas (modelos 303, 347, 390) con
workbook.ToDataSet() - Escribir el contenido del
DataTablede vuelta en XLSX conSetCellValuepara presentaciones a la AEAT - Vincular
DataTablea controles de revisión comoDataGridViewcon una única asignaciónDataSource - Alimentar
SqlBulkCopydirectamente desde unDataTablepara inserciones masivas en la BD de cumplimiento
Para profundizar en tus conocimientos de IronXL, explora estos temas relacionados:
- Exportar DataSet y DataTable -- referencia completa de la API
- Convertir Excel a DataTable en C# sin OleDb
- Tutorial de exportación de DataTable de C# a Excel
- Exportar DataTable a Excel desde ASP.NET
- La forma más rápida de exportar una DataTable a Excel
- Cargar y leer archivos Excel en C#
- Exportar archivos Excel con formato
- Leer archivos Excel en C#: prácticas recomendadas
- Selección y manipulación de rangos en Excel con C#
- Importar datos de Excel a una aplicación C#
Empieza con una licencia de prueba gratuita de IronXL para ejecutar estos ejemplos en tus propios proyectos. Cuando esté listo para la implementación en producción, adquiera una licencia o póngase en contacto con el equipo para orientación sobre licencias.
Preguntas Frecuentes
¿Cómo exportar una DataTable de registros SII a un fichero XLSX para la AEAT con IronXL sin Office?
Cree un WorkBook con WorkBook.Create(), añada una hoja con CreateWorkSheet(), escriba los encabezados SII (NIF, fecha, base imponible, cuota IVA) con SetCellValue() y las filas del DataTable en un bucle, y guarde con workbook.SaveAs('sii-registros.xlsx'). IronXL funciona en Linux/Docker sin Office.
¿Cómo cumplir la LOPDGDD al exportar DataTable de operaciones AEAT a XLSX?
Use worksheet['A1:D{lastRow}'].ToDataTable(true) para exportar únicamente las columnas requeridas por la declaración AEAT específica (principio de minimización). No incluya campos de datos personales (domicilios, información sensible) que no sean necesarios para el modelo 303, 347 o 390.
¿Puede IronXL convertir un libro XLSX con hojas para los modelos 303, 347 y 390 en un DataSet?
Sí. Llame a workbook.ToDataSet() para convertir cada hoja del libro en un DataTable dentro del DataSet. Acceda a cada declaración con dataSet.Tables['Modelo303'], dataSet.Tables['Modelo347'], etc. IronXL ejecuta esta operación en Linux/Docker sin Office.
¿Cómo insertar masivamente registros SII de un DataTable en SQL Server con SqlBulkCopy?
Cargue el fichero XLSX con WorkBook.Load(), llame a worksheet.ToDataTable(true) para obtener el DataTable, y páselo a SqlBulkCopy.WriteToServer(dataTable). Configure ColumnMappings para mapear las columnas SII a los campos de la base de datos de declaraciones.
¿Puede IronXL exportar DataTable de registros TicketBAI o VeriFactu a XLSX?
Sí. IronXL permite exportar cualquier DataTable (incluidos registros de TicketBAI de Bizkaia/Gipuzkoa/Araba y datos de VeriFactu bajo el Real Decreto-Ley 15/2025) a XLSX en Linux/Docker sin Office. Use SetCellValue() para escribir los campos obligatorios de cada sistema.
¿Cómo filtrar operaciones del modelo 347 superiores a 3.005,06 € con LINQ sobre una DataTable?
Use dt.AsEnumerable().Where(row => row.Field
¿IronXL funciona sin Microsoft Office para exportar DataTable en servidores Linux de la AEAT?
Sí. IronXL no requiere Microsoft Office ni registro COM. Se ejecuta en Linux, macOS, Docker y Azure con .NET Framework 4.6.2+ y .NET 5-10, siendo la opción adecuada para servidores de cumplimiento SII/AEAT en entornos cloud sin licencias Office.



