I have an Excel .xlsx file. I want to read data from the file and write data back to the file; no graphics, equations, images, just data.
I tried connecting using the types at System.Data.OleDb:
using System.Data.OleDb;
var fileName = #"C:\ExcelFile.xlsx";
var connectionString =
"Provider=Microsoft.ACE.OLEDB.12.0;" +
$"Data Source={fileName};" +
"Extended Properties=\"Excel 12.0;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text\"";
using var conn = new OleDbConnection(connectionString);
conn.Open();
but I get the following error:
The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.
I know that I can install the Microsoft Access Database Engine 2016 Redistributable, but I want to do this without installing additional software.
How can I do this?
For starters, you may well have the driver already installed, but only for 32-bit programs, while your program is running under 64-bit (or vice versa, but that's less common).
You can force a specific environment in your .csproj file. To force 32-bit, use:
<PropertyGroup>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
and to force 64-bit:
<PropertyGroup>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
If the driver has been installed in the other environment, your code should connect successfully.
NB. You can list the available providers for the current environment using code like the following:
using System.Data;
using System.Data.OleDb;
using System.Linq;
using static System.Console;
var oleEnum = new OleDbEnumerator();
var data =
oleEnum.GetElements()
.Rows
.Cast<DataRow>()
.Select(row => (
name: row["SOURCES_NAME"] as string,
descr: row["SOURCES_DESCRIPTION"] as string
))
.OrderBy(descr => descr);
foreach (var (name, descr) in data) {
WriteLine($"{name,-30}{descr}");
}
What if you don't have the Microsoft.ACE.OLEDB.12.0 provider in either environment? If you can convert your .xlsx file to an .xls file, you could use the Microsoft Jet 4.0 OLE DB Provider, which has been installed in every version of Windows since Windows 2000 (only available for 32-bit).
Set the PlatformTarget to x86 (32-bit) as above. Then, edit the connection string to use the older provider:
using System.Data.OleDb;
var fileName = #"C:\ExcelFile.xls";
// note the changes to Provider and the first value in Extended Properties
var connectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
$"Data Source={fileName};" +
"Extended Properties=\"Excel 8.0;HDR=NO;TypeGuessRows=0;ImportMixedTypes=Text\"";
using var conn = new OleDbConnection(connectionString);
conn.Open();
Once you have an open OleDbConnection, you can read and write data using the standard ADO .NET command idioms for interacting with a data source:
using System.Data;
using System.Data.OleDb;
var ds = new DataSet();
using (var conn = new OleDbConnection(connectionString)) {
conn.Open();
// assuming the first worksheet is called Sheet1
using (var cmd = conn.CreateCommand()) {
cmd.CommandText = "UPDATE [Sheet1$] SET Field1 = \"AB\" WHERE Field2 = 2";
cmd.ExecuteNonQuery();
}
using (var cmd1 = conn.CreateCommand()) {
cmd1.CommandText = "SELECT * FROM [Sheet1$]";
var adapter = new OleDbDataAdapter(cmd);
adapter.Fill(ds);
}
};
NB. I found that in order to update data I needed to remove the IMEX=1 value from the connection string, per this answer.
If you must use an .xlsx file, and you only need to read data from the Excel file, you could use the ExcelDataReader NuGet package in your project.
Then, you could write code like the following:
using System.IO;
using ExcelDataReader;
// The following line is required on .NET Core / .NET 5+
// see https://github.com/ExcelDataReader/ExcelDataReader#important-note-on-net-core
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
DataSet ds = null;
using (var stream = File.Open(#"C:\ExcelFile.xlsx", FileMode.Open, FileAccess.Read)) {
using var reader = ExcelReaderFactory.CreateReader(stream);
ds = reader.AsDataSet();
}
Another alternative you might consider is to use the Office Open XML SDK, which supports both reading and writing. I think this is a good starting point -- it shows both how to read from a given cell, and how to write information back into a cell.
Related
I am implementing SQLCipher into a Xamarin.Forms application. I thought everything was working until I noticed that the DB that was being created by the X.F. application was actually a SQLite3 DB w/o encryption or a password. After looking into it for a while, I haven't been able to find a solution. I am encountering an exception that says
System.InvalidOperationException: 'You specified a password in the connection string, but the native SQLite library you're using doesn't support encryption.'
I currently have 4 projects in this solution. The standard 3 in XamarinForms (Default PCL for cross platform stuff, Project.Android, and Project.iOS). In addition to those 3, I have a custom PCL that is labeled Project.Core. This PCL is responsible for all DataAccess since it implements the Repository Pattern, Unit Of Work, DbContext, etc.
In this 4th project, and within my DbContext.cs class, I have this:
// Added for more context
using System;
using System.IO;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Xamarin.Forms;
private SqliteConnection connection;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
string connStr = Path.Combine(
path1: Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
path2: "App.db");
string passStr = deviceIdentifier;
string path = Path.GetDirectoryName(connStr);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
// Check if db file exists
if (!File.Exists(connStr))
{
FileStream stream = File.Create(connStr);
stream.Close();
}
// DOCS => https://learn.microsoft.com/en-us/dotnet/standard/data/sqlite/encryption?tabs=netcore-cli
// => https://www.bricelam.net/2016/06/13/sqlite-encryption.html
var connectionString = new SqliteConnectionStringBuilder()
{
DataSource = connStr,
Mode = SqliteOpenMode.ReadWriteCreate,
Password = passStr
}.ToString();
// NOTE: THIS IS WHERE THE EXCEPTION IS THROWN!!!
// THE CODE BELOW THIS IS AN ALTERNATE ROUTE THAT DOENS'T WORK EITHER
**connection.Open();**
// This code doesn't throw anything, but it doesn't key the DB either
using (SqliteCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT quote($password);";
command.Parameters.AddWithValue("$password", passStr);
string escapedPassword = (string)command.ExecuteScalar(); // Protects against SQL injection
command.CommandText = "PRAGMA key = " + escapedPassword /*+ ";"*/;
command.Parameters.Clear();
command.ExecuteNonQuery();
}
#if DEBUG
optionsBuilder.EnableSensitiveDataLogging();
#endif
optionsBuilder.UseSqlite(connection);
SQLitePCL.Batteries_V2.Init();
}
Through my research it appears there might be an issue with one of the SQLite/SQLCipher packages in this PCL (the PCL is targeting .NET Standard 2.0 for reference).
I currently have:
Microsoft.Data.Sqlite.Core 3.1.1 (w/ dependencies on Microsoft.Data.Sqlite.dll & SQLitePCLRaw.core 2.0.2)
SQLitePCLRaw.bundle_sqlcipher 1.1.14 (w dependencies on SQLitePCLRaw.core 2.0.2, SQLitePCLRaw.batteries_sqlcipher.dll, SQLitePCLRaw.batteries_v2.dll)
A couple of other things to note:
When viewing SQLitePCL namespace, it shows the package as being sqlitepclraw.bundle_e_sqlite3 instead of having a reference to sqlcipher.
\.nuget\packages\sqlitepclraw.bundle_e_sqlite3\2.0.2\lib\netstandard2.0\SQLitePCLRaw.batteries_v2.dll
I believe there may be an issue with that dependency, but I'm not sure and would appreciate any assistance!
Thanks in advance.
PS - Can provide more information as requested
Found a working solution.
After looking into the packages, I found that replacing the existing SQLitePCLRaw bundle package with SQLitePCLRaw.bundle_zetetic found here, resolved the issues connecting and maintaining an encrypted database.
Working code snippet is:
// StringBuilder here, and the SqliteConnection below are
// from the Microsoft.Data.Sqlite namespace v3.1.1
var connectionString = new SqliteConnectionStringBuilder()
{
DataSource = connStr,
Mode = SqliteOpenMode.ReadWriteCreate,
Password = passStr
}.ToString();
connection = new SqliteConnection(connectionString);
connection.Open();
I am trying to parse from excel format to json.Below is the tried code I am getting problem with "OleDbConnection". I tried different solutions but nothing seems to work.
using System;
using System.Linq;
using System.Data;
using System.Data.OleDb;
using System.Data.Common;
using Newtonsoft.Json;
using System.IO;
namespace ResumeParsing
{
class Program
{
static void Main(string[] args)
{
var pathToExcel = #"C:\Users\Admin\Desktop\resumeexcelformat.xlsx";
var sheetName = "Sheet1";
var destinationPath = #"C:\path\to\save\json\file.json";
//Use this connection string if you have Office 2007+ drivers installed and
//your data is saved in a .xlsx file
var connectionString = $#"
Provider=Microsoft.ACE.OLEDB.12.0;
Data Source={pathToExcel};
Extended Properties=""Excel 12.0 Xml;HDR=YES""
";
//Creating and opening a data connection to the Excel sheet
using (var conn = new OleDbConnection(connectionString))
{
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = $"SELECT * FROM [{sheetName}$]";
using (var rdr = cmd.ExecuteReader())
{
//LINQ query - when executed will create anonymous objects for each row
var query = rdr.Cast<DbDataRecord>().Select(row => new {
Prefix = row[1],
FirstName = row[2],
MiddleName = row[3],
Surname = row[4]
});
//Generates JSON from the LINQ query
var json = JsonConvert.SerializeObject(query);
//Write the file to the destination path
File.WriteAllText(destinationPath, json);
}
}
}
}
}
Through google I tried to add reference but in my project there is no assembly option and it is showing "no items found" in that to check whether system.data is checked or not.See the image also. Can any please tell how to resolve this error?
Important is adding System.Data.dll, because OleDb needs it.
But in your code sample you are already doing it.
Please try to remove the nuget package, clean project, close VS, reinstall package and do a rebuild.
My requirement is that i have 2l data in excel/CSV file which has email id in each row, I have to import those data at one shot, i.e bulk copy to SQL server by verifying one data(email) at a time.
You could also use Microsoft Visual Studio's Business Intelligence tools. By creating a SSIS (SQL Server Integration Services) project you can use various drag and drop tools to create "packages" (or jobs if you wish) which you can execute to perform jobs like these.
You can import data from a wide variety of data sources including Excel, CSV, MySQL, SQL Server and Hadoop to name a few.
You can also write that data from those sources to not only SQL Server but a wide variety of other data destinations as well.
I am using Visual Studio 2015 with the Business Intelligence packages installed.
What I would recommend is:
Start Visual Studio and open a new SSIS (SQL Server Integration Services) project.
Under the control flow tab. Add a new Data Flow task to the control flow area.
Double click on the control flow item or navigate to the Data Flow tab.
Make sure you data flow item is selected. (Should be if you double clicked it.)
From there you can use the Source and Destination Assistants to transport your data.
Once done setting up you source, destination, data transformations and checks. You can hit Start and it will execute the package.
P.S: You can also use the script component in the data flow tab to write custom C# script if you want to.
If we had an example of the Schema (Table structure) you were transporting from and to it would have helped with providing an example.
Best of luck
I have specified the connection strings for the Excel files of both 2003 and 2007 or higher formats in the Web.Config file.
<add name = "Excel03ConString" connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties='Excel 8.0;HDR=YES'"/>
<add name = "Excel07+ConString" connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties='Excel 8.0;HDR=YES'"/>
You will need to import the following namespaces.
using System.IO;
using System.Data;
using System.Data.OleDb;
using System.Data.SqlClient;
using System.Configuration;
Add the following code :
//Upload and save the file
string excelPath = Server.MapPath("~/Files/") + Path.GetFileName(FileUpload1.PostedFile.FileName);
FileUpload1.SaveAs(excelPath);
string conString = string.Empty;
string extension = Path.GetExtension(FileUpload1.PostedFile.FileName);
switch (extension)
{
case ".xls": //Excel 97-03
conString = ConfigurationManager.ConnectionStrings["Excel03ConString"].ConnectionString;
break;
case ".xlsx": //Excel 07 or higher
conString = ConfigurationManager.ConnectionStrings["Excel07+ConString"].ConnectionString;
break;
}
conString = string.Format(conString, excelPath);
using (OleDbConnection excel_con = new OleDbConnection(conString))
{
excel_con.Open();
string sheet1 = excel_con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null).Rows[0]["TABLE_NAME"].ToString();
DataTable dtExcelData = new DataTable();
//[OPTIONAL]: It is recommended as otherwise the data will be considered as String by default.
dtExcelData.Columns.AddRange(new DataColumn[3] { new DataColumn("Id", typeof(int)),
new DataColumn("Name", typeof(string)),
new DataColumn("Salary",typeof(decimal)) });
using (OleDbDataAdapter oda = new OleDbDataAdapter("SELECT * FROM [" + sheet1 + "]", excel_con))
{
oda.Fill(dtExcelData);
}
excel_con.Close();
string consString = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
using (SqlConnection con = new SqlConnection(consString))
{
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(con))
{
//Set the database table name
sqlBulkCopy.DestinationTableName = "dbo.tblPersons";
//[OPTIONAL]: Map the Excel columns with that of the database table
sqlBulkCopy.ColumnMappings.Add("Id", "PersonId");
sqlBulkCopy.ColumnMappings.Add("Name", "Name");
sqlBulkCopy.ColumnMappings.Add("Salary", "Salary");
con.Open();
sqlBulkCopy.WriteToServer(dtExcelData);
con.Close();
}
}
}
I'm trying to make a connection to a DB2 Database sitting on our AS400 (ISeries). I can connect to is successfully using the connection string but once I try to access the Tables I get this error: CPF9812: File SELECT in library *LIBL not found.
At this point I'm just trying to see if i can access the data in the table GLPCT.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.OleDb;
using System.Data;
namespace Testing_Connection_to_GLDBFA
{
class Program
{
static void Main(string[] args)
{
string connectionstring = "Provider=IBMDARLA.DataSource.1;Data Source=INFINIUM;Persist Security Info=True;Password=MyPassword;User ID=UserID;Initial Catalog=S06947A4;Default Collection=GLDBFA";
string querySTring = "";
DataTable schema;
int i = 0;
using( OleDbConnection cn = new OleDbConnection(connectionstring))
{
querySTring = "SELECT * FROM GLPCT";
OleDbCommand command = new OleDbCommand(querySTring, cn);
cn.Open();
OleDbDataReader reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader[0].ToString());
i++;
if (i == 20)
break;
}
cn.Close();
}
}
}
}
Any help or guidance is greatly appreciated.
Thanks in advance.
I'd expect to see the following error:
CPF9812: File GLPCT in library USERID not found.
As by default when using SQL naming the system will implicitly qualify unqualified table names with the user ID. For details, see here
It appears you are using an OLE DB provider instead of the .NET provider
If you want to use the library list, you'll need use system naming and ensure that the library list is configured on the connection.
For the OLEDB providers, you want to set the Library List and Naming Convention
<connection>.Open('Provider=IBMDA400;Data Source=SystemA;Library List=lib1,lib2, *USRLIBL;Naming Convention=1', 'Userid', 'Password');
For .NET provider, it's LibraryList and Naming properties.
Lastly, if you want to stay with the OLE DB provider, you might consider using the IBMDASQL instead of the IBMDARLA one.
I am working on writing a simple program to import an excel sheet into my database but I am running into an error of:
Could not find installable ISAM
I am not sure what this means and after hours of searching with so many different topics I have turned to SO. There is a lot of talk of Jet and ACE where I am not sure what the difference is but here is the rundown: I have an excel file called test or test1 and I just want to import the first sheet in the file. here is my source code so far:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.OleDb;
using System.Data.Common;
using System.Data.SqlClient;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
string filePath = null;
public Form1()
{
InitializeComponent();
}
//Method to check database connection
private void button1_Click(object sender, EventArgs e)
{
string connetionString = null;
SqlConnection cnn;
connetionString = "Data Source=Zach-PC;Initial Catalog=master;Integrated Security=SSPI;";
cnn = new SqlConnection(connetionString);
try
{
cnn.Open();
MessageBox.Show("Connection Open ! ");
cnn.Close();
}
catch (Exception ex)
{
MessageBox.Show("Can not open connection ! ");
}
}
//Method to select a file
private void button2_Click(object sender, EventArgs e)
{
string excelConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:/Users/Zach/Documents/test1.xls;Extended Properties=Excel 12.0,HDR=Yes;IMEX=1";
// Create Connection to Excel Workbook
using (OleDbConnection connection =
new OleDbConnection(excelConnectionString))
{
OleDbCommand command = new OleDbCommand
("Select * FROM [Sheet1$]", connection);
connection.Open(); //HERE IS WHERE THE ERROR IS
// Create DbDataReader to Data Worksheet
using (DbDataReader dr = command.ExecuteReader())
{
// SQL Server Connection String
string sqlConnectionString = "Data Source=Zach-PC;Initial Catalog=master;Integrated Security=True";
// Bulk Copy to SQL Server
using (SqlBulkCopy bulkCopy =
new SqlBulkCopy(sqlConnectionString))
{
bulkCopy.DestinationTableName = "Table";
bulkCopy.WriteToServer(dr);
MessageBox.Show("Data Exoprted To Sql Server Succefully");
}
}
}
}
}
}
Am I approaching this in the right manor?
You need to wrap Extended Properties part of the connection string in the quotation marks:
// here and here
// --> v v
string excelConnectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:/Users/Zach/Documents/test1.xls;Extended Properties=""Excel 12.0,HDR=Yes;IMEX=1""";
The Office oledb driver is probably not installed on your computer. You should download it from microsoft website. After the installation, your code should run.
If you are reading office 2007 (or newer) excel files then I will suggest to use Open source library Epplus to read the excel file.It is purely .NET library and you wont be dependent on oledb driver.
epplus
EPPlus is a .net library that reads and writes Excel 2007/2010 files using the Open Office Xml format (xlsx).
you can easily read an excel file into datatable using this library. have a look at this thread
How convert stream excel file to datatable C#?