How to close ExcelPackage using EPPlus in C#? - c#

I'm using epplus to write in a file an extense quantity of information in an excel template, but then I need to close the ExcelPackage as to be usable with the Excel application. It throws me this exception: "System.Runtime.InteropServices.COMException (0x800A03EC): Exception from HRESULT: 0x800A03EC"
private void FillCardsSheet()
{
xlPackage = new ExcelPackage(Template);
wsCards = xlPackage.Workbook.Worksheets[4];
string command = "SELECT * FROM dbo_serial_cards WHERE type <> 'EXT' AND LEFT([device_tag], 2) <> '!!'";
OleDbCommand cmd = new OleDbCommand(command, CON);
OleDbDataReader reader = cmd.ExecuteReader();
int row = 1;
while (reader.Read())
{
row++;
for (int col = 1; col <= 16; col++)
{
wsCards.Cells[row, col].Value = reader.GetValue(col - 1);
}
}
xlPackage.SaveAs(Template);
xlPackage.Dispose();
}

Hard to say without more details about your connection and objects. What is 'Template'? Might help if you say which line is generating the error (like #mason mentioned). That is a COM error you seem to be getting so it could be with the db connection or maybe the package itself. Since the package is being managed outside the method make sure it is not locked or closed.
This worked fine for me connection to a local SQL Server db:
[TestMethod]
public void SQL_Reader_Test()
{
var Template = new FileInfo(#"c:\temp\temp.xlsx");
if (Template.Exists)
Template.Delete();
var xlPackage = new ExcelPackage(Template);
//var wsCards = xlPackage.Workbook.Worksheets[4];
var wsCards = xlPackage.Workbook.Worksheets.Add("Cards");
//const string constring = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\temp\northwind.mdb;Persist Security Info=False;";
const string constring = #"Provider=SQLNCLI11;Data Source=MYMACHINENAME\SQLEXPRESS;Initial Catalog=AdventureWorks;UID=AdventureWorks; Pwd=AdventureWorks";
using (var CON = new OleDbConnection(constring))
{
CON.Open();
//string command = "SELECT * FROM dbo_serial_cards WHERE type <> 'EXT' AND LEFT([device_tag], 2) <> '!!'";
const string command = "SELECT * FROM Person.Address";
var cmd = new OleDbCommand(command, CON);
var reader = cmd.ExecuteReader();
int row = 1;
while (reader.Read())
{
row++;
//for (int col = 1; col <= 16; col++)
for (int col = 1; col <= reader.FieldCount; col++)
{
wsCards.Cells[row, col].Value = reader.GetValue(col - 1);
}
}
xlPackage.SaveAs(Template);
xlPackage.Dispose();
}
}

Try to use the ExcelPackage within an Using-Block:
using (ExcelPackage xlsPackage = new ExcelPackage(Template))
{
// Your Code
xlPackage.SaveAs(Template);
}

Related

Getting System.Data.SqlClient.SqlException (0x80131904): Incorrect syntax near 'OfficeOpenXml'. Error message

I'm trying to import Excel sheet data into the DB via SSIS script task, I'm continuously getting the above error message.
The Excel file has 3 sheet, and we have separate table for each sheet of that Excel file in the database.
Also I'm not getting any error in the region Namespaces.
Can anyone help, what I'm missing here?
public void Main()
{
try
{
string filePath;
filePath = Dts.Variables["FilePath1"].Value.ToString();
ReadXLS(filePath);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
Dts.TaskResult = (int)ScriptResults.Success;
}
}
public void ReadXLS(string FilePath)
{
FileInfo existingFile = new FileInfo(FilePath);
using (ExcelPackage package = new ExcelPackage(existingFile))
{
string eachVal = "";
int wsheet = package.Workbook.Worksheets.Count;
for (int sheet = 0; sheet<wsheet; sheet++)
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[sheet];
string SheetNames = worksheet.Names.ToString();
int rowCount = worksheet.Dimension.End.Row;
int colCount = worksheet.Dimension.End.Column;
for (int row = 2; row <= rowCount; row++)
{
string queryString = "Insert into [Billing_]" + SheetNames + "values(";
queryString += "(";
for (int col = 1; col <= colCount; col++)
{
eachVal = worksheet.Cells[row, col].Value?.ToString().Trim();
queryString += "'" + eachVal + "',";
}
queryString = queryString.Remove(queryString.Length - 1, 1);
queryString += ")";
runQuery(queryString);
}
}
private void runQuery(string QueryString)
{
string connectionString = #"Data Source = ./; Initial Catalog = Testing; Integrated Security = SSPI;";
string commandText = QueryString;
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(commandText, conn))
{
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
}

Set table style. C# - closed xml

I am looking for a way to apply a table style to the inserted data in an excel file.
I use the library closed xml
How can I do it?
Sample table I want to get
using (XLWorkbook wb = new XLWorkbook(excel))
{ IXLWorksheet ws = wb.Worksheets.Last();
string Qry;
using (SqlCommand cmd = new SqlCommand(Qry, sqlConn))
{
sqlConn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
System.Data.DataTable schemaTable = dr.GetSchemaTable();
int i = 1;
foreach (DataRow rowt in schemaTable.Rows)
{
while (dr.Read())
{
row++;
for (int j = 0; j < dr.FieldCount; j++)
{
if (!dr.IsDBNull(j))
{
switch (dr.GetDataTypeName(j))
{
case "Varchar2":
string s = dr.GetString(j);
if (s.Substring(0, 1) == "=")
s = " " + s;
ws.Cell(row, j + 1).Value = s;
break;
case "nvarchar":
ws.Cell(row, j + 1).Value = dr.GetString(j);
break;
default:
break;
}}}}}}}
Based on the ClosedXML documentation:
// create the Excel workbook
var wb = new XLWorkbook();
// creates the worksheet
var ws = wb.AddWorksheet("Sheet1");
// the range for which you want to add a table style
var range = ws.Range(1, 1, 5, 5);
// create the actual table
var table = range.CreateTable();
// apply style
namesTable.Theme = XLTableTheme.TableStyleLight12;

OleDbDataReader skips first record

I have the following code :
OleDbDataReader xlsReader =
new OleDbCommand("Select * from [" +spreadSheetName + "]", xlsFileConnection).
ExecuteReader();
In the spreadSheetName parameter i keep my file name.
The connection string for xlsFileConnection was set as
"Provider=Microsoft.Jet.OLEDB.4.0;
Data Source='<directory path>';
Extended Properties='text; HDR=No; FMT=Delimited'"
When i start to execute while (xlsReader.Read()) i take a row #2 but not #1 from data source.
The first suggestion was that HDR parameter has invalid value but it seems it's ok.
There are better and easier ways to reading xlsx files, if I were you I would grab closedXML from nuget and this code to read your excel file into a data table
public void ProcessExcel(string fileName)
{
_dt = ImportSheet(fileName);
dgContacts.ItemsSource = _dt.DefaultView;
}
public static DataTable ImportSheet(string fileName)
{
var datatable = new DataTable();
var workbook = new XLWorkbook(fileName);
var xlWorksheet = workbook.Worksheet(1);
var range = xlWorksheet.Range(xlWorksheet.FirstCellUsed(), xlWorksheet.LastCellUsed());
var col = range.ColumnCount();
var row = range.RowCount();
datatable.Clear();
for (var i = 1; i <= col; i++)
{
var column = xlWorksheet.Cell(1, i);
datatable.Columns.Add(column.Value.ToString());
}
var firstHeadRow = 0;
foreach (var item in range.Rows())
{
if (firstHeadRow != 0)
{
var array = new object[col];
for (var y = 1; y <= col; y++)
{
array[y - 1] = item.Cell(y).Value;
}
datatable.Rows.Add(array);
}
firstHeadRow++;
}
return datatable;
}
The grab the data out of your datatable as you need.
This is live and working code, so you just need to copy and paste

How to convert datatype before Importing Excel file to Sql database

Here I have this Import from excel file to sql database class. It was working correctly till now but as my excel file cells are all strings type , So when Importing , the datatype does not match as sql database. How to convert it to their respective datatype before importing?
public static void ImportToSql(string excelfilepath)
{
string myexceldataquery = "select LocalSKU,ItemName, QOH,Price,Discontinued,Barcode,Integer2,Integer3,SalePrice,SaleOn,Price2 from [sheet1$]";
try
{
string sexcelconnectionstring = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source =" + excelfilepath + "; Extended Properties=\"Excel 12.0; HDR=Yes; IMEX=2\"";
string ssqlconnectionstring = "Data Source=DELL\\SQLSERVER1;Trusted_Connection=True;DATABASE=Test;CONNECTION RESET=FALSE";
SqlConnection sqlconn = new SqlConnection(ssqlconnectionstring);
//series of commands to bulk copy data from the excel file into our sql table
OleDbConnection oledbconn = new OleDbConnection(sexcelconnectionstring);
OleDbCommand oledbcmd = new OleDbCommand(myexceldataquery, oledbconn);
oledbconn.Open();
OleDbDataReader dr = oledbcmd.ExecuteReader();
SqlCommand sqlcmd = new SqlCommand(#"MERGE Inventory AS target
USING (select LocalSKU,ItemName, QOH,Price,Discontinued,Barcode,Integer2,Integer3,SalePrice,SaleOn,Price2 from #source) as source
ON (source.LocalSKU = target.LocalSKU)
WHEN MATCHED THEN
UPDATE SET ItemName=source.ItemName,Price=source.Price,Discontinued=source.Discontinued,Barcode=source.Barcode,Integer2=source.Integer2,Integer3 = source.QOH,SalePrice=source.SalePrice,SaleOn=source.SaleOn,Price2=source.Price2;", sqlconn);
SqlParameter param;
param = sqlcmd.Parameters.AddWithValue("#source",dr);
param.SqlDbType = SqlDbType.Structured;
param.TypeName = "dbo.InventoryType";
sqlconn.Open();
sqlcmd.ExecuteNonQuery();
sqlconn.Close();
while (dr.Read())
{
}
oledbconn.Close();
Console.WriteLine(".xlsx file imported succssessfully into database.");
}
The easiest thing to do would be to convert them in your SQL statement by using CAST:
SqlCommand sqlcmd = new SqlCommand(
#"MERGE Inventory AS target
USING (select LocalSKU, ItemName, QOH = CAST(QOH AS int)
, Price = CAST(Price AS decimal(10,2)), Discontinued = CAST(Discontinued AS bit)
, Barcode, Integer2 = CAST(Integer2 AS int)
, Integer3 = CAST(Integer3 AS int), SalePrice = CAST(SalePrice AS decimal(10,2))
, SaleOn, Price2 = CAST(Price2 AS decimal(10,2)) from #source) as source
ON (source.LocalSKU = target.LocalSKU)
WHEN MATCHED THEN
UPDATE (. . . )
I'm guessing on some of the conversions, but you get the idea. You'll need to make sure that the data in the spreadsheet all match the datatypes you want to convert them to, as one mistake will cause the whole statement to fail. Something more robust will take a lot more code.
First browse the excel file and put data in datagrid and then read datagrid row one by one.
i give you 2 function for that. one is browse the excel file and put data in datagrid and second one is read datagrid and put record in database
Excel Export Function
private void export_btn_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel.Application ExcelApp =
new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel._Workbook ExcelBook;
Microsoft.Office.Interop.Excel._Worksheet ExcelSheet;
int i = 0;
int j = 0;
//create object of excel
ExcelBook = (Microsoft.Office.Interop.Excel._Workbook)ExcelApp.Workbooks.Add(1);
ExcelSheet = (Microsoft.Office.Interop.Excel._Worksheet)ExcelBook.ActiveSheet;
//export header
for (i = 1; i <= this.dataGridView1.Columns.Count; i++)
{
ExcelSheet.Cells[1, i] = this.dataGridView1.Columns[i - 1].HeaderText;
}
//export data
for (i = 1; i <= this.dataGridView1.RowCount; i++)
{
for (j = 1; j <= dataGridView1.Columns.Count; j++)
{
ExcelSheet.Cells[i + 1, j] = dataGridView1.Rows[i - 1].Cells[j - 1].Value;
}
}
ExcelApp.Visible = true;
//set font Khmer OS System to data range
Microsoft.Office.Interop.Excel.Range myRange = ExcelSheet.get_Range(
ExcelSheet.Cells[1, 1],
ExcelSheet.Cells[this.dataGridView1.RowCount + 1,
this.dataGridView1.Columns.Count]);
Microsoft.Office.Interop.Excel.Font x = myRange.Font;
x.Name = "Arial";
x.Size = 10;
//set bold font to column header
myRange = ExcelSheet.get_Range(ExcelSheet.Cells[1, 1],
ExcelSheet.Cells[1, this.dataGridView1.Columns.Count]);
x = myRange.Font;
x.Bold = true;
//autofit all columns
myRange.EntireColumn.AutoFit();
ExcelApp.ActiveWorkbook.SaveCopyAs("E:\\reports.xlsx");
ExcelApp.ActiveWorkbook.Saved = true;
ExcelApp.Quit();
MessageBox.Show("Excel file created,you can find the file E:\\reports.xlsx");
//
ExcelSheet = null;
ExcelBook = null;
ExcelApp = null;
}
Read Datagrid
public void readDataGrid()
{
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
try
{
//Here read one by one cell and convert it into your required datatype and store it in
String rowcell1 = dataGridView1.Rows[i].Cells[0].Value.ToString();
}
catch (Exception err)
{
}
count++;
}
}
I this is help you.

How to obtain the underlying SQL types for query results in .NET/C#?

For example, the following code prints "System.Int32", not "int":
string connArgs = "..."; // use your settings here
string query = "SELECT 1";
using (SqlConnection conn = new SqlConnection(connArgs)) {
conn.Open();
SqlCommand cmd = new SqlCommand(query, conn);
using (SqlDataReader reader = cmd.ExecuteReader())
for (int col = 0; col < reader.VisibleFieldCount; ++col)
Console.WriteLine(reader.GetFieldType(col));
}
How can I obtain the underlying SQL type, not just its equivalent .NET system type?
You can use a GetDataTypeName method for that:
Gets a string representing the data type of the specified column.
for (int col = 0; col < reader.VisibleFieldCount; ++col) {
Console.WriteLine(reader.GetDataTypeName(col));
}

Categories