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
Related
I have images stored in my database, there are about 500 of them. I have stored them as an "image" data type. There is also eid field in each row which is unique.
I need to download ALL these images into a SINGLE folder. The name of the image should be the EID of the row.
I am using C# & asp.net 4.5 with SQL Server 2012.
Can you please advise?
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Data.SqlClient;
using System.Net;
using Ionic.Zip;
namespace test.admin
{
public partial class downloadImages : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void submit_Click(object sender, EventArgs e)
{
// delete existing images in the folder
var di = new DirectoryInfo(Server.MapPath("~/images"));
foreach (var file in di.EnumerateFiles())
{
file.Delete();
}
// create images and store them in the images folder
DataTable dt = GetData("SELECT * FROM mytable");
for (int i = 0; i < dt.Rows.Count; i++)
{
byte[] bytes = (byte[])dt.Rows[i]["photo"];
File.WriteAllBytes(Server.MapPath("~/images/" + dt.Rows[i]["eID"] + ".jpg"), bytes);
}
// use this to download the zip file
using (ZipFile zip = new ZipFile())
{
zip.AlternateEncodingUsage = ZipOption.AsNecessary;
zip.AddDirectory(Server.MapPath("~/images/"))
Response.Clear();
Response.BufferOutput = false;
string zipName = String.Format("sasImages.zip", DateTime.Now.ToString("yyyy-MMM-dd-HHmmss"));
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "attachment; filename=" + zipName);
zip.Save(Response.OutputStream);
Response.End();
}
}
protected void delete_Click(object sender, EventArgs e)
{
// delete existing images in the folder
var di = new DirectoryInfo(Server.MapPath("~/images"));
foreach (var file in di.EnumerateFiles())
{
file.Delete();
}
string script = "alert('All files in the folder deleted successfully');";
ClientScript.RegisterClientScriptBlock(this.GetType(), "Alert", script, true);
}
private DataTable GetData(string query)
{
DataTable dt = new DataTable();
string constr = ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString;
using (SqlConnection con = new SqlConnection(constr))
{
using (SqlCommand cmd = new SqlCommand(query))
{
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.CommandType = CommandType.Text;
cmd.Connection = con;
sda.SelectCommand = cmd;
sda.Fill(dt);
}
}
return dt;
}
}
}
}
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.
I'm using an MDF database with the OpenFileDialog class to import a single CSV file to a database. That works fine for a single CSV file, but I need to open and process multiple CSV files in bulk.
How can I improve my code? I've tried using a for loop.
Here is my code to process a single CSV file:
ofd.Filter = "CSV files (*.csv) | *.csv; | CSV PRN files (*.prn,) |*.prn;";
ofd.FileName = "";
ofd.ShowDialog();
DataTable dt = new DataTable();
string line = null;
int i = 0;
using (StreamReader sr = File.OpenText(ofd.FileName))
{
while ((line = sr.ReadLine()) != null)
{
string[] data = line.Split(',');
if (data.Length > 0)
{
if (i == 0)
{
foreach (var item in data)
{
dt.Columns.Add(new DataColumn());
}
i++;
}
DataRow row = dt.NewRow();
row.ItemArray = data;
dt.Rows.Add(row);
}
}
}
string symbolName = dt.Rows[1][0].ToString();
string strConnection =
#"Data Source =.\SQLEXPRESS; AttachDbFilename = C:\USERS\JEF\DOCUMENTS\DATABASE1.MDF; Integrated Security = True; Connect Timeout = 30; User Instance = True";
SqlConnection condb2 = new SqlConnection(strConnection);
string createTablerow ="create table ["+symbolName+"] (code1 VARCHAR(100) COLLATE Arabic_CI_AI_KS_WS,date1 varchar(50),open1 varchar(50),high1 varchar(50),low1 varchar(50),close1 varchar(50),vol1 varchar(50))";
using (SqlConnection connection = new SqlConnection(strConnection))
{
SqlCommand command1 = new SqlCommand(createTablerow, connection);
connection.Open();
command1.ExecuteNonQuery();
}
using (SqlConnection cn = new SqlConnection(strConnection))
{
cn.Open();
using (SqlBulkCopy copy = new SqlBulkCopy(cn))
{
copy.ColumnMappings.Add(0, "code1");
copy.ColumnMappings.Add(1, "date1");
copy.ColumnMappings.Add(2, "open1");
copy.ColumnMappings.Add(3, "high1");
copy.ColumnMappings.Add(4, "low1");
copy.ColumnMappings.Add(5, "close1");
copy.ColumnMappings.Add(6, "vol1");
copy.DestinationTableName = "[" + symbolName + "]";
copy.WriteToServer(dt);
}
}
I moved some of you code around to make it more efficient :
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;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ofd.FileName = "";
ofd.ShowDialog();
string line = null;
int i = 0;
string strConnection =
#"Data Source =.\SQLEXPRESS; AttachDbFilename = C:\USERS\JEF\DOCUMENTS\DATABASE1.MDF; Integrated Security = True; Connect Timeout = 30; User Instance = True";
using (SqlConnection connection = new SqlConnection(strConnection))
{
connection.Open();
SqlBulkCopy copy = new SqlBulkCopy(connection);
copy.ColumnMappings.Add(0, "code1");
copy.ColumnMappings.Add(1, "date1");
copy.ColumnMappings.Add(2, "open1");
copy.ColumnMappings.Add(3, "high1");
copy.ColumnMappings.Add(4, "low1");
copy.ColumnMappings.Add(5, "close1");
copy.ColumnMappings.Add(6, "vol1");
foreach (string file in ofd.FileNames)
{
using (StreamReader sr = File.OpenText(file))
{
DataTable dt = new DataTable();
while ((line = sr.ReadLine()) != null)
{
string[] data = line.Split(',');
if (data.Length > 0)
{
if (i == 0)
{
foreach (var item in data)
{
dt.Columns.Add(new DataColumn());
}
i++;
}
DataRow row = dt.NewRow();
row.ItemArray = data;
dt.Rows.Add(row);
}
}
string symbolName = dt.Rows[1][0].ToString();
string createTable = string.Format("create table [{0}] (code1 VARCHAR(100) COLLATE Arabic_CI_AI_KS_WS,date1 varchar(50),open1 varchar(50),high1 varchar(50),low1 varchar(50),close1 varchar(50),vol1 varchar(50))",
symbolName);
using (SqlCommand command1 = new SqlCommand(createTable, connection))
{
command1.ExecuteNonQuery();
copy.DestinationTableName = "[" + symbolName + "]";
copy.WriteToServer(dt);
}
}
}
}
}
}
}
In order to process multiple files at once you will need to use a parallel code. Your use of "for" was a nice try, but "for" loops still run concurrently, which means one at a time.
The easiest way to achieve this parallel processing in this case would be to use Parallel.Foreach, here is a Microsoft guide about it: https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-write-a-simple-parallel-foreach-loop
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...
Hello guys i have a form application for renaming files which get data from excel and i want to get excel column names with datagridview what should i do?
edit:excel image on comments
path = dataGridView1.Rows[i].Cells["K1"].Value.ToString();
path2 = dataGridView1.Rows[i].Cells["K2"].Value.ToString();
those K1 and K2 are the names of one of the excel column name, but i want it to work on all excel columns how it can be done?
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.IO;
namespace WindowsFormsApplication7
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
OleDbConnection baglan = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Users\\STAJ\\AppData\\Roaming\\Skype\\My Skype Received Files\\ETKB-Aktarim-Test(1).xlsx ; Extended Properties='Excel 12.0 xml;HDR=YES;'");
baglan.Open();
string sorgu = "select * from [Sheet1$] ";
OleDbDataAdapter data_adaptor = new OleDbDataAdapter(sorgu, baglan);
baglan.Close();
DataTable dt = new DataTable();
data_adaptor.Fill(dt);
dataGridView1.DataSource = dt;
string path="";
string path2 = "";
string newFileName = "";
string oldFileName = "";
int i = 0;
foreach (DataGridViewRow row in dataGridView1.Rows)
{
try
{
path = dataGridView1.Rows[i].Cells["K1"].Value.ToString();
path2 = dataGridView1.Rows[i].Cells["K2"].Value.ToString();
oldFileName = path ;
newFileName = path2;
if (File.Exists(oldFileName))
{
File.Move(oldFileName, newFileName);
}
i++;
}
catch (Exception ex)
{
MessageBox.Show("DOSYA ADI DEGISTIRILDI");
}
}
}
}
}