I am looking for a library which would do something like that:
Lib.Configure.Cells(...)
Lib.CreateExcelFileFromMyObject<MyObject>(myObject);
I believe a long ago I come across such library but cant remember it's name.
May be some one can point me to the right direction.
I know two ways to read or write excel files.
As already said you can access excel files through the office interop interface as described here. This method is slow, but you can do almost everything what you can do with the gui of excel.
Use the OleDb database interface. This possibility is much faster than the first one, but its restricted to data. So as far as i know it is not possible to read/write formatting e.g. some background color of a cell. With the following function you will get the entire data of a sheet of an excel file at once:
private DataSet ConnectAndLoad(string filepath, string sheet)
{
DataSet data_set = new DataSet();
OleDbConnection oledbConn = new OleDbConnection(String.Format("Provider=Microsoft.Ace.Oledb.12.0;Data Source={0};Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1;\"", filepath));
string query = "Select * From [" + sheet + "$]";
try
{
oledbConn.Open();
OleDbCommand oledbCmd = new OleDbCommand(query, oledbConn);
OleDbDataAdapter ole_da = new OleDbDataAdapter(oledbCmd);
ole_da.Fill(data_set);
}
catch (OleDbException ex)
{
// do some error catching
}
finally
{
oledbConn.Close();
}
return data_set;
}
you can use
using Microsoft.Office.Interop
namespace to access the ms products
For that first you need to do is add that reference to your project
Related
I have an MVC application which allows an admin user to upload 2 different excel file onto the system; the controller then creates a dataset with the excel data and then populates either a "Schools" or a "School2" database with the dataset using an SqlBulkCopy.
These uploads work perfect when I test them locally using IIS Express, although the same version deployed to AWS elastic beanstalk throws an error when I press the import button. As far as I am aware, this is due to my AWS RDS needing access to the OleDB provider jet drivers; something which I can not do because these drivers can not just be installed on an AWS RDS like they can be on an EC2 instance.
So my plan is to change my upload controller around to accept .csv files instead of excel files. This should solve my problem and allow my upload buttons to work after being deployed on AWS. Could someone help me/point me in the right direction to change my controller to support .csv instead of excel please?
Upload Controller:
namespace CampBookingSys.Controllers
{
public class UploadController : Controller
{
SqlConnection con = new SqlConnection(#"Data Source=bookingdb.cwln7mwjvxdd.eu-west-1.rds.amazonaws.com,1433;Initial Catalog=modeldb;User ID=craig1990;Password=27Oct90!;Database=modeldb;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False");
OleDbConnection Econ;
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
string filename = Guid.NewGuid() + Path.GetExtension(file.FileName);
string filepath = "/excelfolder/" + filename;
file.SaveAs(Path.Combine(Server.MapPath("/excelfolder"), filename));
InsertExceldata(filepath, filename);
return View();
}
[HttpPost]
public ActionResult Index2(HttpPostedFileBase file)
{
string filename = Guid.NewGuid() + Path.GetExtension(file.FileName);
string filepath = "/excelfolder/" + filename;
file.SaveAs(Path.Combine(Server.MapPath("/excelfolder"), filename));
InsertExceldata2(filepath, filename);
return RedirectToAction("Index");
}
private void ExcelConn(string filepath)
{
string constr = string.Format(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=""Excel 12.0 Xml;HDR=YES;""", filepath);
Econ = new OleDbConnection(constr);
}
private void InsertExceldata(string filepath, string filename)
{
string fullpath = Server.MapPath("/excelfolder/") + filename;
ExcelConn(fullpath);
string query = string.Format("Select * from [{0}]", "Sheet1$");
OleDbCommand Ecom = new OleDbCommand(query, Econ);
Econ.Open();
DataSet ds = new DataSet();
OleDbDataAdapter oda = new OleDbDataAdapter(query, Econ);
Econ.Close();
oda.Fill(ds);
DataTable dt = ds.Tables[0];
SqlBulkCopy objbulk = new SqlBulkCopy(con);
objbulk.DestinationTableName = "dbo.Schools";
objbulk.ColumnMappings.Add("AcademicYear", "AcademicYear");
objbulk.ColumnMappings.Add("RollNumber", "RollNumber");
objbulk.ColumnMappings.Add("OfficialSchoolName", "OfficialSchoolName");
objbulk.ColumnMappings.Add("Address1", "Address1");
objbulk.ColumnMappings.Add("Address2", "Address2");
objbulk.ColumnMappings.Add("Address3", "Address3");
objbulk.ColumnMappings.Add("Address4", "Address4");
objbulk.ColumnMappings.Add("County", "County");
objbulk.ColumnMappings.Add("Eircode", "Eircode");
objbulk.ColumnMappings.Add("LocalAuthority", "LocalAuthority");
objbulk.ColumnMappings.Add("X", "X");
objbulk.ColumnMappings.Add("Y", "Y");
objbulk.ColumnMappings.Add("ITMEast", "ITMEast");
objbulk.ColumnMappings.Add("ITMNorth", "ITMNorth");
objbulk.ColumnMappings.Add("Latitude", "Latitude");
objbulk.ColumnMappings.Add("Longitude", "Longitude");
con.Open();
objbulk.WriteToServer(dt);
con.Close();
}
private void InsertExceldata2(string filepath, string filename)
{
string fullpath = Server.MapPath("/excelfolder/") + filename;
ExcelConn(fullpath);
string query = string.Format("Select * from [{0}]", "Sheet1$");
OleDbCommand Ecom = new OleDbCommand(query, Econ);
Econ.Open();
DataSet ds = new DataSet();
OleDbDataAdapter oda = new OleDbDataAdapter(query, Econ);
Econ.Close();
oda.Fill(ds);
DataTable dt = ds.Tables[0];
SqlBulkCopy objbulk = new SqlBulkCopy(con);
objbulk.DestinationTableName = "dbo.School2";
objbulk.ColumnMappings.Add("RollNumber", "RollNumber");
objbulk.ColumnMappings.Add("OfficialSchoolName", "OfficialSchoolName");
objbulk.ColumnMappings.Add("Address1", "Address1");
objbulk.ColumnMappings.Add("Address2", "Address2");
objbulk.ColumnMappings.Add("Address3", "Address3");
objbulk.ColumnMappings.Add("Address4", "Address4");
objbulk.ColumnMappings.Add("County", "County");
objbulk.ColumnMappings.Add("Eircode", "Eircode");
objbulk.ColumnMappings.Add("PhoneNumber", "PhoneNumber");
objbulk.ColumnMappings.Add("Email", "Email");
objbulk.ColumnMappings.Add("PrincipalName", "PrincipalName");
objbulk.ColumnMappings.Add("DeisSchool", "DeisSchool");
objbulk.ColumnMappings.Add("SchoolGender", "SchoolGender");
objbulk.ColumnMappings.Add("PupilAttendanceType", "PupilAttendanceType");
objbulk.ColumnMappings.Add("IrishClassification", "IrishClassification");
objbulk.ColumnMappings.Add("GaeltachtArea", "GaeltachtArea");
objbulk.ColumnMappings.Add("FeePayingSchool", "FeePayingSchool");
objbulk.ColumnMappings.Add("Religion", "Religion");
objbulk.ColumnMappings.Add("OpenClosedStatus", "OpenClosedStatus");
objbulk.ColumnMappings.Add("TotalGirls", "TotalGirls");
objbulk.ColumnMappings.Add("TotalBoys", "TotalBoys");
objbulk.ColumnMappings.Add("TotalPupils", "TotalPupils");
con.Open();
objbulk.WriteToServer(dt);
con.Close();
}
}
}
My first advice is to do bulk inserts in the DBMS, not in code. Doing them via code is only prone to add addtional issues.
As far as parsing the .xlsx files go, the OleDB driver is propably unessesary. There are a few basic rules for working with office formats:
if you can limit it to the new ones (.xlsx), you can use the OpenXML SDK. Or any of the Wrappers people made around it. Or even just the .ZipArchive and XMLReader classes.
if you need to support the old formats (.xls) too, you got to use the (t)rusty Office COM Interop. This has all the usual issue of COM Interop, and aditionally needs office installed and a Interactive session
for any given Display Technology and Problem, there might be a 3rd option. But those are few and far in between. As we always got the Interop to fall back on, we never developed a complete Office processing class like so many other languages have.
I would put OlebDB in that last category - a rare and very specific solution.
It always advise for using the first option.
And Officer COM Interop should be silently burried, with the old formats being removed from the file format options. Considering this is a WebApplication that will likely run as services, you will not get the nesseary interactive session anyway.
Of course accepting .csv is also an option. And indeed Excel has full .CSV support.
I have a program which is supposed to open, edit, create and save access databases. For saving I copy an empty database with just the tables (just to avoid going through the hassle of creating every table and column etc) and try to fill it with values via the TableAdapterManager.UpdateAll method.
string _TemplateConnectString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};";
_connection = new OleDbConnection(string.Format(_TemplateConnectString, dlg.FileName));
_connection.Open();
DataSet1TableAdapters.TableAdapterManager tam=new TableAdapterManager();
tam.Connection = _connection;
try
{
tam.UpdateAll(dataset);
}
catch (System.Exception ex)
{
MessageBox.Show("Update failed");
}
It finishes with no exceptions but the values don't get inserted into the new database.
Also as far as I know the UpdateAll method only updates modified row so if I open some db and it inserts it's rows, it will not take them into account even though there are not in the database that I am trying to fill.
I have also tried filling the database with the ADODB and ADOX extensions but all the solutions I found with those was a lot of hardcoding and no regards for hierarchy, keys, etc.
Is there a way to force insert everything in the new database?
Is your template database in the Visual Studio project directory? It might have something to do with Visual Studio copying the database to the bin/debug or bin/release folder...
Try to use the right Data source database name, here an
example with an excel file:
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=c:\somepath\ExcelFile.xls;" & _
"Extended Properties=""Excel 8.0;HDR=Yes;"";"
A clumsy solution but it works. I iterate the tables of the dataset and save the via an sql string generator like this:
void SaveTable(DataTable dt)
{
string[] inserts;
try
{
inserts = SqlHelper.GenerateInserts(dt, null, null, null);
foreach (string s in inserts)
{
OleDbCommand cmd = new OleDbCommand();
cmd.CommandText = s;
cmd.Connection = _connection;
int n = cmd.ExecuteNonQuery();
}
}
catch (Exception e)
{
SaveOk = false;
}
}
I found the SqlHelper somewhere on this site, but completely lost where, unforunately. So here is the pastebin with it https://pastebin.com/iCMVuYyu
I am certain I have missed something obvious.
A simple task is before me: 'Upload an Excel (2003) file via ASP.NET on a Forms page and push the contents of that file to a DataTable in preparation for data- validation / storage'.
Those operations work fine already when applied to a locally stored edition of the file -- for that I simply utilize the OleDbConnection-ConnectionString "String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=Excel 8.0;", fileName)" from an OleDbDataAdapter.
However, trying to repeat that with an uploaded edition of the very same file (via a FileUpload control), on the line where I fill the OleDbDataAdapter I receive the error ["The Microsoft Jet database engine could not find the object "Sheet1$". Make sure the object exists and that you spell its name and the path name correctly."] An error so generic and painful -- still I'm unsure where to look next. I am guessing the connection-string structure is illegitimate for an uploaded file.
I searched through StackOverflow and MSDN and even around the web with no success thus far, but the search terms may be overly ubiquitous. Am I required to actually find a local repository for saving the uploaded file to prior to attempting a parse of it's content? Can I not simply construct a connection to a 'file in memory'? In case it concerns the answer, the uploaded files are not anticipated to ever exceed 200 kb in size.
Sincere thanks in advance for any assistance provided...
What I do in this situation is build a Parser class that will temporarily save the file, process it, then delete that temporary file when disposed. Something like:
public class ExcelParser : IDisposable
{
string filename;
string connStr = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source={0}; Extended Properties=\"Excel 12.0 Xml;HDR=YES\"";
public ExcelParser(HttpPostedFile file)
{
filename = String.Format("{0}{1}.xlsx", System.IO.Path.GetTempPath(), Guid.NewGuid().ToString());
file.SaveAs(filename);
}
public MyData Process()
{
OleDbConnection conn = new OleDbConnection(String.Format(connStr, filename));
conn.Open();
OleDbCommand cmd = new OleDbCommand("Select * From [Sheet1$]", conn);
OleDbDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
// Build Data to return
}
reader.Close();
conn.Close();
return data; // Return data you built
}
public void Dispose()
{
File.Delete(filename);
}
}
You could then use it as such:
using (ExcelParser parser = new ExcelParser(file))
{
var results = parser.Process();
// Do stuff
}
I'm having a problem opening a DBF file - I need to open it, read everything and process it. I tried several solutions (ODBC/OLEDB), several connection string, but nothing worked so far.
The problem is, when I execute the SQL command to get everything from the file, nothing gets returned - no rows. What's even more odd, the content of the DBF file being opened get deleted.
See the code I have:
public override bool OpenFile(string fileName, string subFileName = "")
{
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Path.GetDirectoryName(fileName) + ";Extended Properties=dBASE IV;User ID=;Password=;");
try
{
if (con.State == ConnectionState.Closed) { con.Open(); }
OleDbDataAdapter da = new OleDbDataAdapter("select * from " + Path.GetFileName(fileName), con);
DataSet ds = new DataSet();
da.Fill(ds);
con.Close();
int i = ds.Tables[0].Rows.Count;
return true;
}
catch
{
return false;
}
}
I debugged the code and watched the file being opend in Windows Explorer. When it reached this line:
da.Fill(ds);
the size of the file dropped to only a few Bytes (from hundreds of kB).
My next thought was to make the DBF file read only. That however cause an "unexpected exception from an external driver".
So my question is - what the heck? I'm sure the file is not corrupt, it is a direct export from some DB. (No, I do not have access to that DB). I can also open that file in MS Office no problem.
I cannot share the DBF file - it contains confidential data.
Two things... just because its a .DBF file extension might night mean its a Dbase IV file. It might actually be that of Visual Foxpro. That said, I would look into downloading and installing the Visual Foxpro OleDB driver from Microsoft download. Next, the OleDbConnection is pointing to the path that has the actual tables (you already have that).
The query itself, shouldn't care about the extension, so I would change your call to get just then name via "Path.GetFileNameWithoutExtension"
It might be a combination of the two.
Connection string for VFP provider
"Provider=VFPOLEDB.1;Data Source=" + FullPathToDatabase
This is not the exact answer but it will help you to find the issue.
Try to give an inline connection string and select query to make sure problem is not with building those. Catch the exception and check the details of it.
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\folder;Extended Properties=dBASE IV;User ID=;Password=;"); // give your path directly
try
{
con.Open();
OleDbDataAdapter da = new OleDbDataAdapter("select * from tblCustomers.DBF", con); // update this query with your table name
DataSet ds = new DataSet();
da.Fill(ds);
con.Close();
int i = ds.Tables[0].Rows.Count;
return true;
}
catch(Exception e)
{
var error = e.ToString();
// check error details
return false;
}
private void Form1_Load(object sender, EventArgs e)
{
GetDataTable(#"C:\Documents and Settings\agordon\Desktop\ACTIVITYEX.log");
}
public System.Data.DataTable GetDataTable(string strFileName)
{
System.Data.OleDb.OleDbConnection conn =
new System.Data.OleDb.OleDbConnection
("Provider=Microsoft.Jet.OleDb.4.0; Data Source = "
+ System.IO.Path.GetDirectoryName(strFileName)
+ ";Extended Properties = \"Text;HDR=YES;FMT=TabDelimited\"");
conn.Open();
string strQuery = "SELECT * FROM [" + System.IO.Path.GetFileName(strFileName) + "]";
System.Data.OleDb.OleDbDataAdapter adapter = new System.Data.OleDb.OleDbDataAdapter(strQuery, conn);
System.Data.DataTable ds = new System.Data.DataTable("CSV File");
adapter.Fill(ds);
return ds;
}
when THE SAME file is named .csv it does not give me an error; however when i rename it to .log it says Cannot update. Database or object is read-only. on adapter.Fill
is this a compiler error?
An old post, but I just stepped into that problem.
Please refer to this article : https://support.microsoft.com/en-us/kb/245407
Long story short : Jet Engine only accepts a few file extension when reading CSV File (Extended properties=TEXT,etc..).
Solutions :
rename your file in a temp folder when reading it
read it with another mecanism than JET (standard File.io.ReadAllLines)
Add the extension in the windows registry as pointed out by antonio Bukala
No, it's a not a compiler error. If anything it's an error from the OleDb Jet engine. I have ran into enough problems with Jet in the past so I usually avoid it. You might save yourself lots of debugging time by using TextFieldParser.
*.log is disabled extension, AFAIK only way is registry change on machine that will run this code, see MS Knowledge base article