I am following the following an example to Export data from table/stored proc to Excel.
https://www.c-sharpcorner.com/UploadFile/rahul4_saxena/how-to-export-multiple-data-tables-to-multiple-worksheets-in/
The only difference is that since I have an Angular/MVC project, I am using this code in the class. In the method 'Export_To_Excel()', there is
Response.Clear(); and other Response methods. But I was getting error, "Response does not exist in current context." So I tried changing to fully qualified reference:
HttpContext.Current.Response or
System.Web.HttpContext.Current.Response
but now I get error, "An object reference not set to an instance of Object"
Please guide what to do? Here is my complete code in cs file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using ClosedXML.Excel;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace MyProject.DAL
{
public class CreateWorkBook
{
private DataTable getAllEmployeesList()
{
using (SqlConnection con = Connection.GetConnection())
{
using (SqlCommand cmd = new SqlCommand(#"SELECT * FROM Employee ORDER BY ID;"))
{
using (SqlDataAdapter da = new SqlDataAdapter())
{
DataTable dt = new DataTable();
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
da.SelectCommand = cmd;
da.Fill(dt);
return dt;
}
}
}
}
private DataTable getAllEmployeesOrderList()
{
using (SqlConnection con = Connection.GetConnection())
{
using (SqlCommand cmd = new SqlCommand("SELECT * FROM OrderDetails ORDER BY Order_ID;"))
{
using (SqlDataAdapter da = new SqlDataAdapter())
{
DataTable dt = new DataTable();
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
da.SelectCommand = cmd;
da.Fill(dt);
return dt;
}
}
}
}
public DataSet getDataSetExportToExcel()
{
DataSet ds = new DataSet();
DataTable dtEmp = new DataTable("Employee");
dtEmp = getAllEmployeesList();
DataTable dtEmpOrder = new DataTable("Order List");
dtEmpOrder = getAllEmployeesOrderList();
ds.Tables.Add(dtEmp);
ds.Tables.Add(dtEmpOrder);
return ds;
}
public string SetToExport(string channel, string assets )
{
string status = Export_To_Excel();
return "success";
}
protected string Export_To_Excel()
{
try
{
DataSet ds = getDataSetExportToExcel();
using (XLWorkbook wb = new XLWorkbook())
{
wb.Worksheets.Add(ds);
wb.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
wb.Style.Font.Bold = true;
// Error here –
//An object reference not set to an instance of Object
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.Buffer = true;
System.Web.HttpContext.Current.Response.Charset = "";
System.Web.HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
System.Web.HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename= SubmissionForm.xlsx");
using (MemoryStream MyMemoryStream = new MemoryStream())
{
wb.SaveAs(MyMemoryStream);
MyMemoryStream.WriteTo(System.Web.HttpContext.Current.Response.OutputStream);
System.Web.HttpContext.Current.Response.Flush();
System.Web.HttpContext.Current.Response.End();
}
}
return "success";
}
catch (Exception e)
{
throw e;
//return "Export to Excel failed";
}
}
}
}
As #Scott mentioned in the comments you should break this up into smaller problems.
First create code to successfully generate the excel file. This should return a byte[]. To simplify things you could create a console app that saves the file locally to PC to begin with, test that and make sure its working.
Once part 1 is working copy the code that generates the byte[] into your web project. Then you just need to figure out how to download a file in MVC to the client.
The below code may help.
// CreateWorkBook class
public byte[] Export_To_Excel()
{
DataSet ds = getDataSetExportToExcel();
using (XLWorkbook wb = new XLWorkbook())
{
wb.Worksheets.Add(ds);
wb.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
wb.Style.Font.Bold = true;
using (MemoryStream myMemoryStream = new MemoryStream())
{
wb.SaveAs(myMemoryStream);
// return memory stream as byte array
return myMemoryStream.ToArray();
}
}
}
Then in your controller you can use FileResult to return the excel file. Below is an example of how you might accomplish it in an MVC controller.
// your MVC controller
[HttpGet]
public FileResult DownloadExcel()
{
var createExcel = new CreateWorkBook();
byte[] excelFile = null;
try
{
excelFile = createExcel.Export_To_Excel();
}
catch (Exception ex)
{
// handle exception
}
string fileType = #"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
string fileName = "excel.xlsx";
return File(excelFile, fileType, fileName);
}
just don't use the commented code below which is not relevant with Excel export operation.
//HttpContext.Current.Response.Clear();
//HttpContext.Current.Response.Buffer = true;
//System.Web.HttpContext.Current.Response.Charset = "";
//System.Web.HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
//System.Web.HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename= SubmissionForm.xlsx");
using (MemoryStream MyMemoryStream = new MemoryStream())
{
wb.SaveAs(MyMemoryStream);
//you need to replace below line according to your need. **
//MyMemoryStream.WriteTo(System.Web.HttpContext.Current.Response.OutputStream);
//System.Web.HttpContext.Current.Response.Flush();
//System.Web.HttpContext.Current.Response.End();
}
** Without knowing the structure of your project and your intend it is impossible to tell you the right way of downloading/saving this file.
Related
I'm really new with C# and ASP.Net, I can say that i'm learning over the road. What i need to do is run an stored procedure and create an Excel file with the response. This is my code so far of the controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using ConfigurationSettings = System.Configuration.ConfigurationManager;
using System.IO;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace NewSalesReport.Controllers
{
public class NewSalesReportController : Controller
{
class Program
{
static void Main()
{
string inline = ConfigurationSettings.AppSettings["ConectionString"];
using (SqlConnection toConect = new SqlConnection(inline))
{
using (SqlCommand cmd = new SqlCommand("DaReport", toConect))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#StartDate", SqlDbType.DateTime));
cmd.Parameters.Add(new SqlParameter("#EndDate", SqlDbType.DateTime));
using (SqlDataAdapter adp = new SqlDataAdapter(cmd))
{
DataSet ds = new DataSet();
adp.Fill(ds);
/*if (ds != null)
{
//Console.Write("It is not Empty");
} */
}
}
}
}
private void SetDataExcel(object result)
{
GridView grid = new GridView();
grid.DataSource = result;
StringWriter strwritter = new StringWriter();
HtmlTextWriter htmltextwrtter = new HtmlTextWriter(strwritter);
grid.RenderControl(htmltextwrtter);
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=reportExcel.xls");
Response.ContentType = "application/ms-excel";
Response.Output.Write(strwritter.ToString());
Response.Flush();
Response.End();
strwritter.Dispose();
htmltextwrtter.Dispose();
}
public ActionResult GetAprovedForPay(DateTime? fi = null, DateTime? ff = null)
{
var result = _repo.GetAprovedForPay(fi, ff);
SetDataExcel(result);
return null;
}
}
}
}
Someone is helping me with a few advices, and he told me that i need to pass the first table as a parameter: ds.Tables[0], but he didn't explain how.
Also, when i run the compiler shows an error which says that i need a
reference object for the field, method or property Controller.Response.
Someone can help me, please with this two issues? As i said, i'm new with this hole thing of .Net.
Thanx in advance
An object reference is required for the non-static field, method or property error occurred because you're calling Controller.Response from a method which has return type of void instead of ActionResult.
First, remove inner class Program and rename Main() method to other name (also remove static if necessary). Sounds like the code includes Main() method previously used in console/WinForms application, and you should change it to avoid confusion.
Second, remove Response usage and use FileResult to return file for download as in example below:
public FileResult SetDataExcel(object obj)
{
GridView grid = new GridView();
grid.AutoGeneratedColumns = true; // automatically generate all columns from data source
grid.DataSource = result;
StringWriter strwritter = new StringWriter();
HtmlTextWriter htmltextwrtter = new HtmlTextWriter(strwritter);
grid.RenderControl(htmltextwrtter);
string path = Server.MapPath("~/path/to/filename.xls");
using (var sw = new StreamWriter(path))
{
sw.Write(strwriter.ToString());
}
var savedFile = new FileStream(path, FileMode.Open);
return File(savedFile, "application/ms-excel");
}
Finally, you can use redirection to call SetDataExcel which returns the file:
public ActionResult GetAprovedForPay(DateTime? fi = null, DateTime? ff = null)
{
var result = _repo.GetAprovedForPay(fi, ff);
return RedirectToAction("SetDataExcel", new { obj = result });
}
Note: Regarding data binding for GridView, if AutoGeneratedColumns set to true then you can use ds.Tables[0] as data source (see the reference here):
string inline = ConfigurationSettings.AppSettings["ConectionString"];
using (SqlConnection toConect = new SqlConnection(inline))
{
using (SqlCommand cmd = new SqlCommand("DaReport", toConect))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("#StartDate", SqlDbType.DateTime));
cmd.Parameters.Add(new SqlParameter("#EndDate", SqlDbType.DateTime));
using (SqlDataAdapter adp = new SqlDataAdapter(cmd))
{
DataSet ds = new DataSet();
adp.Fill(ds);
grid.DataSource = ds.Tables[0];
grid.DataBind();
}
}
}
I'm trying to retrieve values from an Oracle database using C# WebMethod, ajax and JavaScript, I have another page with exactly all the same functions and methods (using MSSQL Database) and work fine, but now I want to do it with Oracle. This is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Oracle.DataAccess.Client;
using System.Data;
using System.Configuration;
/// <summary>
/// Summary description for OracleConexion
/// </summary>
public class OracleConexion
{
OracleConnection conn;
DataTable dt;
OracleDataAdapter da;
OracleDataReader dr;
DataSet ds;
OracleCommand cmd;
public OracleConexion()
{
conn = new OracleConnection("Data Source = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = ***.**.**.***)(PORT = ****)))(CONNECT_DATA = (SERVER = DEDICATED)(SID = *****))); User Id = *****; Password = ****;");
}
private void Open()
{
string canConnect;
try
{
conn.Open();
canConnect = "Nice";
}
catch (Exception ex)
{
//Code Updated
canConnect = ex.Message.ToString();
}
Console.Write(canConnect);
}
private void Close()
{
try
{
conn.Close();
}
catch (Exception ex)
{
}
}
public DataTable ConsultarTablas(string opcion)
{
dt = new DataTable();
ds = new DataSet();
string sql = "";
switch (opcion)
{
case "Datos":
sql = "Select Component as Result from BOM_Explosion where TOP_MATERIAL = '-FHN7092A-EF' and ROWNUM <= 5;";
break;
}
try
{
Open();
OracleDataAdapter da = new OracleDataAdapter(sql, conn);
da.Fill(ds);
dt = ds.Tables[0];
}
catch (Exception ex)
{
}
finally
{
Close();
}
return dt;
}
}
And this is my WebMethod
[WebMethod]
public string ObtenerDatosNumeroParte()
{
DataTable dt = new DataTable();
dt = conn.ConsultarTablas("Datos");
Ticket ti;
List<Ticket> lista = new List<Ticket>();
for (int i = 0; i < dt.Rows.Count; i++)
{
ti = new Ticket();
ti.Vs = dt.Rows[i]["Result"].ToString();
lista.Add(ti);
ti = null;
}
JavaScriptSerializer js = new JavaScriptSerializer();
string lineas = js.Serialize(lista);
return lineas;
}
Testing it seems like my code do not execute my query and my List always is null, what I'm doing wrong and what can I do to solve it?
Update
Using my string canConnect I get ORA-6413: Connection not open.
I have a .csv file and I'd like to read it into a datagridview (each value into an each column).
I read this file with block note and I see that each value is divided by ";"
I tried to set a datatable but it's not working. This is my code:
string FileName = #"C:\mydir\testcsv.csv";
OleDbConnection conn = new OleDbConnection("Provider=Microsoft.Jet.OleDb.4.0; Data Source = " + Path.GetDirectoryName(FileName) + "; Extended Properties = \"Text;HDR=YES;FMT=Delimited\"");
conn.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM " + Path.GetFileName(FileName), conn);
DataSet ds = new DataSet("Temp");
adapter.Fill(ds);
conn.Close();
dataGridView2.DataSource = ds;
I don't understand where's the error.
Your code worked for me as it is.
I just added one line to the datasource assignment after looking inside the dataset, I saw just one table is inside with name "Table" so I assigned the datamember of the datagridview:
dataGridView1.DataSource = ds;
dataGridView1.DataMember = "Table";
Anyway if I used ';' separator, all the values were in one column... With ',' comma separator it works ok.
The complete code of the form:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string FileName = #"C:\mydir\testcsv.csv";
OleDbConnection conn = new OleDbConnection
("Provider=Microsoft.Jet.OleDb.4.0; Data Source = " +
Path.GetDirectoryName(FileName) +
"; Extended Properties = \"Text;HDR=YES;FMT=Delimited\"");
conn.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter
("SELECT * FROM " + Path.GetFileName(FileName), conn);
DataSet ds = new DataSet("Temp");
adapter.Fill(ds);
conn.Close();
dataGridView1.DataSource = ds;
dataGridView1.DataMember = "Table";
}
}
}
Contents of the csv file:
abc,123
def,456
ijk,789
lmn,111213
For semicolon delimited files you need to add an ini file in your folder containing the csv file. How to do it exactly is described here:
How to specify the delimiter when importing CSV files via OLEDB in C#
For decimal delimiter symbol you have to add the
DecimalSymbol
directive to your Jet ini file.
See the full ini file capabilities documented in MSDN (https://msdn.microsoft.com/en-us/library/ms709353(v=vs.85).aspx)
I use this function by long, long time, after: yourgrid.datasource = function result.
public static DataTable CsvDb(string filename, string separatorChar)
{
var table = new DataTable("Filecsv");
using (var sr = new StreamReader(filename, Encoding.Default))
{
string line;
var i = 0;
while (sr.Peek() >= 0)
{
try
{
line = sr.ReadLine();
if (string.IsNullOrEmpty(line)) continue;
var values = line.Split(new[] { separatorChar }, StringSplitOptions.None);
var row = table.NewRow();
for (var colNum = 0; colNum < values.Length; colNum++)
{
var value = values[colNum];
if (i == 0)
{
table.Columns.Add(value, typeof(String));
}
else
{ row[table.Columns[colNum]] = value; }
}
if (i != 0) table.Rows.Add(row);
}
catch (Exception ex)
{
string cErr = ex.Message;
//if you need the message error
}
i++;
}
}
return table;
}
Try...
I need to write multiple queries to a single CSV file. For example I will generate a report with an Employee Schedule then below that in the same CSV I want to see the employee personal information such as salary, office location, etc. I can return both queries from a single stored procedure thinking it would write one followed by the next, but apparently that's incorrect as only the first result is returned.
My SQL Query is like the following:
SELECT EmployeeSchedule.TaskTime, Employees.EmployeeName, EmployeeSchedule.M, EmployeeSchedule.Tu, EmployeeSchedule.W,
EmployeeSchedule.Th, EmployeeSchedule.F, EmployeeSchedule.Sa, EmployeeSchedule.Su
FROM EmployeeSchedule
INNER JOIN Employees on EmployeeSchedule.EmployeeID = Employees.EmployeeID
WHERE (
EmployeeSchedule.EmployeeID = #EmployeeID AND
EmployeeSchedule.TaskTime >= #ShiftStart AND
EmployeeSchedule.TaskTime <= #ShiftEnd AND
(
(EmployeeSchedule.M=1) AND (EmployeeSchedule.M = #M) OR
(EmployeeSchedule.Tu=1) AND (EmployeeSchedule.Tu = #Tu) OR
(EmployeeSchedule.W=1) AND (EmployeeSchedule.W = #W) OR
(EmployeeSchedule.Th=1) AND (EmployeeSchedule.Th = #Th) OR
(EmployeeSchedule.F=1) AND (EmployeeSchedule.F = #F) OR
(EmployeeSchedule.Sa=1) AND (EmployeeSchedule.Sa = #Sa) OR
(EmployeeSchedule.Su=1) AND (EmployeeSchedule.Su = #Su)
)
)
ORDER BY EmployeeName, TaskTime
SELECT Employees.EmployeeName, Salary, City, AdditionalDetails
FROM EmployeeDetails
INNER JOIN Employees on EmployeeDetails.EmployeeID = Employees.EmployeeID
WHERE Employees.EmployeeID=#EmployeeID
My relevant portion of code is as follows:
public void GenerateEmployeeLog()
{
string employee = Convert.ToString(EmployeesDropDown.SelectedItem.Text);
string sqlConn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection sqlConnection1 = new SqlConnection(sqlConn))
{
try
{
sqlConnection1.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = ("usp_" + proc);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = sqlConnection1;
cmd.Parameters.AddWithValue("EmployeeID", Convert.ToString(EmployeeDropDown.SelectedItem.Value));
cmd.Parameters.AddWithValue("ShiftStart", StartTextBox.Text);
cmd.Parameters.AddWithValue("ShiftEnd", EndTextBox.Text);
cmd.Parameters.AddWithValue("M", MCheckBox.Checked);
cmd.Parameters.AddWithValue("Tu", TuCheckBox.Checked);
cmd.Parameters.AddWithValue("W", WCheckBox.Checked);
cmd.Parameters.AddWithValue("Th", ThCheckBox.Checked);
cmd.Parameters.AddWithValue("F", FCheckBox.Checked);
cmd.Parameters.AddWithValue("Sa", SaCheckBox.Checked);
cmd.Parameters.AddWithValue("Su", SuCheckBox.Checked);
using (SqlDataReader reader = cmd.ExecuteReader())
{
try
{
using (DataTable dt = new DataTable())
{
dt.Load(reader);
using (StreamWriter writer = new StreamWriter(Response.OutputStream))
{
DataConvert.ToCSV(dt, writer, false);
Response.AddHeader("content-disposition", #"attachment;filename=""" + "EmployeeLog - " + employee + #".csv""");
Response.Charset = "";
Response.ContentType = "application/text";
Response.End();
}
}
}
catch (Exception)
{
throw;
}
finally
{
reader.Close();
reader.Dispose();
}
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
sqlConnection1.Close();
sqlConnection1.Dispose();
}
}
}
Any suggestions on how to accomplish what I'm looking for is greatly appreciated.
SOLUTION:
I ended up splitting out the two queries into different stored procedures and made the final modifications to my code, based on suggestions from the accepted answer below.
public void GenerateEmployeeLog()
{
string employee = Convert.ToString(EmployeesDropDown.SelectedItem.Text);
string sqlConn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
using (SqlConnection sqlConnection1 = new SqlConnection(sqlConn))
{
try
{
sqlConnection1.Open();
using (SqlCommand cmd1 = new SqlCommand())
{
cmd1.CommandText = ("usp_" + proc + "_EmployeeDetails");
cmd1.CommandType = CommandType.StoredProcedure;
cmd1.Connection = sqlConnection1;
cmd1.Parameters.AddWithValue("EmployeeID", Convert.ToString(AffiliatesDropDown.SelectedItem.Value));
using (SqlDataReader reader = cmd1.ExecuteReader())
{
try
{
using (dt1 = new DataTable())
{
dt1.Load(reader);
}
}
catch (Exception)
{
throw;
}
finally
{
reader.Close();
reader.Dispose();
}
}
}
using (SqlCommand cmd2 = new SqlCommand())
{
cmd2.CommandText = ("usp_" + proc);
cmd2.CommandType = CommandType.StoredProcedure;
cmd2.Connection = sqlConnection1;
cmd2.Parameters.AddWithValue("EmployeeID", Convert.ToString(EmployeeDropDown.SelectedItem.Value));
cmd2.Parameters.AddWithValue("ShiftStart", StartTextBox.Text);
cmd2.Parameters.AddWithValue("ShiftEnd", EndTextBox.Text);
cmd2.Parameters.AddWithValue("M", MCheckBox.Checked);
cmd2.Parameters.AddWithValue("Tu", TuCheckBox.Checked);
cmd2.Parameters.AddWithValue("W", WCheckBox.Checked);
cmd2.Parameters.AddWithValue("Th", ThCheckBox.Checked);
cmd2.Parameters.AddWithValue("F", FCheckBox.Checked);
cmd2.Parameters.AddWithValue("Sa", SaCheckBox.Checked);
cmd2.Parameters.AddWithValue("Su", SuCheckBox.Checked);
using (SqlDataReader reader = cmd2.ExecuteReader())
{
try
{
using (DataTable dt2 = new DataTable())
{
dt2.Load(reader);
using (StreamWriter writer = new StreamWriter(Response.OutputStream))
{
DataConvert.ToCSV(dt2, writer, false);
writer.WriteLine();
DataConvert.ToCSV(dt1, writer, false);
Response.AddHeader("content-disposition", #"attachment;filename=""" + "EmployeeLog - " + employee + #".csv""");
Response.Charset = "";
Response.ContentType = "application/text";
Response.End();
}
}
}
catch (Exception)
{
throw;
}
finally
{
reader.Close();
reader.Dispose();
}
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
sqlConnection1.Close();
sqlConnection1.Dispose();
}
}
}
I like Mike U's 2nd approach very much, but if you absolutely must have one csv file output, its not pretty, but could you not do something like this?:
using (SqlDataReader reader = cmd.ExecuteReader()){
using (SqlDataReader reader1 = cmd1.ExecuteReader()){
using (DataTable dt = new DataTable()){
using (DataTable dt1 = new DataTable()){
dt.Load(reader);
dt1.Load(reader1);
using (StreamWriter writer = new StreamWriter(Response.OutputStream)){
DataConvert.ToCSV(dt, writer, false);
DataConvert.ToCSV(dt1, writer, false);
...
}}}}}
Judging by the Response stuff, you're doing this on a web page. The problem you're going to run into is that you can only return a single response for a single request. Since you're just sending the DataConvert.ToCSV() output as a response stream, that would mean a different stream for each of the files.
If you're not going to actually display these in HTML, then you'll need to create a ZIP file to store the two different files.
Examples for creating a multi-file ZIP file can be found here: https://msdn.microsoft.com/en-us/library/system.io.compression.zipfile(v=vs.110).aspx
EDIT: A second option would be to emit javascript into the Page_Load event which would call an HTTPHandler which actually runs the two separate queries. This would popup two additional tabs, each with one of the CSV files. You would have to move all this code into a custom HTTPHandler, where the querystring string parameter "t" could determine which of the two queries was run.
protected void btn_OnClick(object sender, EventArgs e)
{
string sysPgLoad = "Sys.Application.add_load(function () {{ {0}; }});";
this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), "employeeLog", string.Format(sysPgLoad, "window.Open('exployeeCsv.axd?t=log')"));
this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), "employeeSal", string.Format(sysPgLoad, "window.Open('exployeeCsv.axd?t=sal')"));
}
I got the error message below when I tried to upload a csv file to a SQL Server table using C# (csv file has no header).
Error Message : "A column named ' ' already belongs to this DataTable"
I tried to find some solutions somewhere on the web but I'm really stuck with it.
My code :
SqlConnection con = new SqlConnection(#"server=.;Initial Catalog=myDtabase;Integrated Security=SSPI;");
string filepath = #"c:\\my_CSV_file.csv";
StreamReader sr = new StreamReader(filepath);
string line = sr.ReadLine();
string[] value = line.Split(',');
DataTable dt = new DataTable();
DataRow row;
foreach (string dc in value)
{
dt.Columns.Add(new DataColumn(dc));
}
while (!sr.EndOfStream)
{
value = sr.ReadLine().Split(',');
if (value.Length == dt.Columns.Count)
{
row = dt.NewRow();
row.ItemArray = value;
dt.Rows.Add(row);
}
}
SqlBulkCopy bc = new SqlBulkCopy(con.ConnectionString, SqlBulkCopyOptions.TableLock);
bc.DestinationTableName = "my_SQLServer_Table";
bc.BatchSize = dt.Rows.Count;
con.Open();
bc.WriteToServer(dt);
bc.Close();
con.Close();
I think this link will help you get this done.
http://forums.asp.net/t/1695615.aspx
As usual, there is more than one way to skin a cat. So, if yo don't like the solution listed above, try this script, which I know will work for you.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Data.SqlClient;
using System.Data.OleDb;
using System.Configuration;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string server = "EXCEL-PC\\EXCELDEVELOPER";
string database = "AdventureWorksLT2012";
string SQLServerConnectionString = String.Format("Data Source={0};Initial Catalog={1};Integrated Security=SSPI", server, database);
string CSVpath = #"C:\Users\Ryan\Documents\Visual Studio 2010\Projects\Bulk Copy from CSV to SQL Server Table\WindowsFormsApplication1\bin"; // CSV file Path
string CSVFileConnectionString = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};;Extended Properties=\"text;HDR=Yes;FMT=Delimited\";", CSVpath);
var AllFiles = new DirectoryInfo(CSVpath).GetFiles("*.CSV");
string File_Name = string.Empty;
foreach (var file in AllFiles)
{
try
{
DataTable dt = new DataTable();
using (OleDbConnection con = new OleDbConnection(CSVFileConnectionString))
{
con.Open();
var csvQuery = string.Format("select * from [{0}]", file.Name);
using (OleDbDataAdapter da = new OleDbDataAdapter(csvQuery, con))
{
da.Fill(dt);
}
}
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(SQLServerConnectionString))
{
bulkCopy.ColumnMappings.Add(0, "MyGroup");
bulkCopy.ColumnMappings.Add(1, "ID");
bulkCopy.ColumnMappings.Add(2, "Name");
bulkCopy.ColumnMappings.Add(3, "Address");
bulkCopy.ColumnMappings.Add(4, "Country");
bulkCopy.DestinationTableName = "AllEmployees";
bulkCopy.BatchSize = 0;
bulkCopy.WriteToServer(dt);
bulkCopy.Close();
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message, "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}
}
}
The CsvHelper NuGet library has an implementation for IDataReader which you can pass into the BulkCopy WriteToServer method. This makes for really simple code and allows you to customize the data import.
using CsvHelper;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System.Globalization;
using System.IO;
public int ReplaceTableWithFile(string table, FileInfo csvFile)
{
using var fileReader = new StreamReader(csvFile.OpenRead());
using var csv = new CsvReader(fileReader, CultureInfo.InvariantCulture);
using var csvDataReader = new CsvDataReader(csv);
var connection = GetDbConnection();
using var command = new SqlBulkCopy(connection);
command.EnableStreaming = true;
command.DestinationTableName = table;
command.WriteToServer(csvDataReader);
return command.RowsCopied;
}
CsvDataReader from CsvHelper NuGet package