C# datatable column datatype - c#

I'm importing data from an excel sheet into a datatable and I'm having a problem/question about the datatypes. When I create the datatable, I add the columns and their datatypes. After this I import the data from excel and this works fine. When I check the datatype of the columns it says what I expect. However, when I try and pass a value to a function I get the message that I'm trying to pass an object type, instead of the datatype I set.
here's my code (it's a simplified dataset):
public void importData(string _file)
{
DataTable dtTest = new DataTable();
dtTest.Columns.Add("a", typeof(Int32));
dtTest.Columns.Add("b", typeof(Int32));
string connString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=\"Excel 12.0 Xml;HDR=YES;IMEX=1\";", _file);
OleDbConnection conn = new OleDbConnection(connString);
conn.Open();
OleDbDataAdapter objAdapter = new OleDbDataAdapter();
string sheetName = "Sheet1";
string sql = "SELECT * FROM [" + sheetName + "$]";
OleDbCommand objCmdSelect = new OleDbCommand(sql, conn);
objAdapter.SelectCommand = objCmdSelect;
objAdapter.Fill(dtTest);
conn.Close();
form.write(dtTest.Rows[0]["a"]);
}
the function 'form.write()' accepts an integer.
when I check the datatype before I try and pass the value to form.write, it says it's Int32.
if (dtTest.Columns[0].DataType == typeof(Int32))
{
//this is true
}
what am I doing wrong?

the function 'form.write()' accepts an integer.
Since form.Write accepts an integer, you need to cast it from object to int:
int a = dtTest.Rows[0].Field<int>("a");
form.write(a);
Late binding is not allowed in C#, you must use the correct type at compile-time.

If I am understanding your post correctly, you may need to cast the value.
form.write(dtTest.Rows[0]["a"]);
I believe it should be:
form.write(Convert.ToInt32(dtTest.Rows[0]["a"]));
Without the Convert.ToInt32() you are referencing an object type.

Related

SqlBulkCopy mapping issue with fullstops in column names

I'm trying to import Excel sheet to SQL Server database. The issue happening is with the column mapping.
If the Column Name in Excel Sheet ends with fullstop (eg: 'No.', 'Name.'), C# is throwing an exception
Message=The given ColumnName 'No.' does not match up with any column
in data source.
But if I remove fullstop, it is working absolutely fine.
The source code for mapping in C# is as follows
private void InsertExcelRecords()
{
string FilePath = "C:\\Upload\\" + FileUpload.FileName;
string fileExtension = Path.GetExtension(FileUpload.PostedFile.FileName);
FileUpload.SaveAs("C:\\Upload\\" + FileUpload.FileName);
ExcelConn(FilePath, fileExtension);
Econ.Open();
DataTable dtExcelSheetName = Econ.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
string getExcelSheetName = dtExcelSheetName.Rows[0]["Table_Name"].ToString();
Query = string.Format("Select * FROM [{0}]", getExcelSheetName + "A7:I");
OleDbCommand Ecom = new OleDbCommand(Query, Econ);
DataSet ds = new DataSet();
OleDbDataAdapter oda = new OleDbDataAdapter(Query, Econ);
Econ.Close();
oda.Fill(ds);
DataTable Exceldt = ds.Tables[0];
connection();
SqlBulkCopy objbulk = new SqlBulkCopy(con);
objbulk.DestinationTableName = "BankTransaction";
objbulk.ColumnMappings.Add("No", "Number");
con.Open();
objbulk.WriteToServer(Exceldt);
con.Close();
}
Please let me know if you need any more information.
You will not be able to retrieve column names with . from an excel sheet using OLEDB or ODBC. Because it is not a valid or recognizable syntax.
'.' typically we use it to distinguish between two [schema].[table].[column] like that.
OLEDB,ODBC Replace column name '.' char with '#'
So you need to replace your code
objbulk.ColumnMappings.Add("No.", "Number")
with
objbulk.ColumnMappings.Add("No#", "Number")

DataSet using first value as column header

I have a piece of code where I want to extract values from the A column of an Excel sheet. Right now, here is the code I'm using and having an issue with:
m_connString = "Provider = Microsoft.ACE.OLEDB.12.0; Data Source = " + m_source + "; Extended properties = 'Excel 12.0; HDR = NO; IMEX = 1;';";
using (OleDbConnection conn = new OleDbConnection(m_connString))
{
conn.Open();
DataTable dt = conn.GetOleDbSchemaGuid(Tables, null);
DataSet ds = new DataSet();
string defaultSheet = ExcelSheets.Rows[0]["TABLE_NAME"].ToString();
OleDbCommand comm = new OleDbCommand("SELECT * FROM [" + defaultSheet + "]", conn);
OleDbDataAdapter adapter = new OleDbDataAdapter(comm);
// Bug appears here
adapter.fill(ds)
// Fill a List<string> with the data found
for (int r = 0; r < ds.Tables[0].Row.Count; r++)
{
m_list.Add(ds.Tables[0].Rows[r][0].ToString();
}
}
What is happening is that, if I have an Excel file with the following content in the A column:
Row1
Row2
Row3
...
RowX
...What I end up getting is all values except for the first value (Row1). It turns out that Row1 is being used as a column name(?) for the DataSet's table. However, I don't want there to be any column names or headers, and I specifically state this in the connection string.
How can I prevent this behavior so I can have all my data placed in the List? Or, failing that, how can I work around this issue and extract Row1 from that DataSet?
Check Microsoft Reference to understand how Extended Properties of the connection HDR=NO works:
Column headings: By default, it is assumed that the first row of your
Excel data source contains columns headings that can be used as field
names. If this is not the case, you must turn this setting off, or
your first row of data "disappears" to be used as field names. This is
done by adding the optional HDR= setting to the Extended Properties of
the connection string. The default, which does not need to be
specified, is HDR=Yes. If you do not have column headings, you need to
specify HDR=No; the provider names your fields F1, F2, etc.
Here is example:
Excel File Data (test.xlsx):
Code:
string m_source = "test.xlsx";
string m_connString = #"Provider = Microsoft.ACE.OLEDB.12.0;
Data Source = " + m_source + #";
Extended properties = 'Excel 12.0;
HDR= NO;
IMEX = 1;';";
using (OleDbConnection conn = new OleDbConnection(m_connString))
{
conn.Open();
string squery = "SELECT f1, f2, f3 FROM [Sheet1$]";
OleDbCommand comm = new OleDbCommand(squery, conn);
OleDbDataAdapter adapter = new OleDbDataAdapter(comm);
DataSet ds = new DataSet();
adapter.Fill(ds);
}
DataSet Visualizer:
Try this way:
DataTable table = ds.Tables[0];
foreach (DataColumn column in table.Columns)
{
string cName = table.Rows[0][column.ColumnName].ToString();
if (!table.Columns.Contains(cName) && cName != "")
{
column.ColumnName = cName;
}
}
change the sql to something along the lines of this
"SELECT * FROM [" + defaultSheet + "] Except Select Top(1)"

Excel file imports - data type

I have been working on a desktop application and I have a little problem with Excel file imports.
Everything is good but when I read the data from the Excel sheet it does not read all the numbers and Alphabets. For example, if the first cell of the column is numbers then it will not read Alphabets from that column. If I change the type to Text for that column manually then everything is good.
Here is my sample code for importing Excel sheet data.
Any ideas?
public static DataSet exceldata(string filelocation)
{
DataSet ds = new DataSet();
OleDbCommand excelCommand = new OleDbCommand();
OleDbDataAdapter excelDataAdapter = new OleDbDataAdapter();
string excelConnStr = String.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0};Extended Properties=\"Excel 4.0;HDR=YES;IMEX=1;Importmixedtypes=text;typeguessrows=0;\"", filelocation);
OleDbConnection excelConn = new OleDbConnection(excelConnStr);
excelConn.Open();
DataTable dtPatterns = new DataTable();
excelCommand = new OleDbCommand("SELECT * FROM [Sheet1$]", excelConn);
excelDataAdapter.SelectCommand = excelCommand;
excelDataAdapter.Fill(dtPatterns);
ds.Tables.Add(dtPatterns);
return ds;
}
System.out.println(cell.toString());//here is the problem
toString() method returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object.
Use cell.getStringCellValue()
instead
cell.toString()
And propor usage needed.
For numeric values you have to use
getNumericCellValue() and put a condition there
if(cell!=null)
{
int type = cell.getCellType();
if (type == HSSFCell.CELL_TYPE_STRING)
System.out.println(cell.getRichStringCellValue().toString());
else if (type == HSSFCell.CELL_TYPE_NUMERIC)
String[] splits = String.valueOf(cell.getNumericCellValue()).split(".");
System.out.println(splits[0]);
else if (type == HSSFCell.CELL_TYPE_BOOLEAN)
System.out.println( cell.getBooleanCellValue());
else if (type == HSSFCell.CELL_TYPE_BLANK)
System.out.println(cell.getColumnIndex() + "] = BLANK CELL");
}

Why My SqlBulkCopy Is Not Working

I am using SqlBulkCopy object to write a datatable into an sql server table. However, everytime I recheck my database it remains intact with no changes. A
I have tried to do Google search to determine my problem but i am unable to resolve it.
The datatable came from an .xls file.
public static DataTable dt = new DataTable();
private void ExportToGrid(String path, String filen)
{
int idx = filen.IndexOf(".");
string tf = filen.Remove(idx, 4);
OleDbConnection MyConnection = null;
DataSet DtSet = null;
OleDbDataAdapter MyCommand = null;
MyConnection = new OleDbConnection("provider=Microsoft.Jet.OLEDB.4.0; Data Source='" + path + "';Extended Properties=Excel 8.0;");
ArrayList TblName = new ArrayList();
MyConnection.Open();
DataTable schemaTable = MyConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
foreach (DataRow row in schemaTable.Rows)
{
TblName.Add(row["TABLE_NAME"]);
}
MyCommand = new System.Data.OleDb.OleDbDataAdapter("select * from [" + TblName[0].ToString() + "]", MyConnection);
DtSet = new System.Data.DataSet();
MyCommand.Fill(DtSet);
MyCommand.FillSchema(DtSet, SchemaType.Source);
DataTable dt = new DataTable();
dt = DtSet.Tables[0];
Session["dt"] = dt;
int x = dt.Rows.Count;
MyConnection.Close();
if (dt.Rows.Count > 0)
{
theGridView.DataSource = dt;
theGridView.DataBind();
}
if (System.IO.File.Exists(path))
{
System.IO.File.Delete(path);
}
}
This is my writer function
private void StartImport()
{
string servername = server;
string database = database;
string tbl = "dbo.LinkDb";
Stopwatch sw = new Stopwatch();
sw.Start();
SqlBulkCopy bulkCopy = new SqlBulkCopy("Data Source=" + servername + ";Initial Catalog=" + database + ";Integrated Security=SSPI", SqlBulkCopyOptions.TableLock);
bulkCopy.DestinationTableName = tbl;
bulkCopy.WriteToServer(dt);
sw.Stop();
lblResult.Visible = true;
lblResult.Text = (sw.ElapsedMilliseconds / 1000.00).ToString();
}
Below are the screenshot of the tables stored in my sql server. I assure you that I have been complying to Case Sensitive rules.
There was no exception thrown and average time elapsed is 0.018 - 0.020 secs
Appreciate any helps.
Thank you
Based on the code you have posted, you are writing an empty datatable to the database. Your "ExportToGrid" method fills dt, a DataTable declared locally, which loses scope outside of the method. Your write function is calling the static DataTable dt which is a new datatable.
Does dt need to be static? it seems as though this could be declared as
private DataTable dt;
then inside "ExportToGrid" instead of declaring another DataTable just instantiate the already declared dt rather than declaring a new one
dt = new DataTable();
Alternatively you could extract the DataTable straight from the GridView during the write Method:
DataTable dt = (DataTable)theGridView.DataSource;
bulkCopy.WriteToServer(dt);
This removes the need for variables outside of the scope of the method.
Lastly since you are storing your datatable within the session (I am not generally an advocate of storing large amounts of data in session variables but without knowing the specifics of your site I cannot really pass judgement), you could use the following:
DataTable dt = (DataTable)Session["dt"];
bulkCopy.WriteToServer(dt);
I dont see anything obvious compared to my use except for the fact that I explicitly map columns from the data table to the database table.
Using cn As New SqlConnection(DataAccessResource.CONNECTIONSTRING)
cn.Open()
Using copy As New SqlBulkCopy(cn)
copy.BulkCopyTimeout = 300
copy.ColumnMappings.Add(0, 0)
copy.ColumnMappings.Add(1, 1)
copy.ColumnMappings.Add(2, 2)
copy.ColumnMappings.Add(3, 3)
copy.DestinationTableName = "Tablename"
copy.WriteToServer(dataset.datatable)
End Using
End Using
Connection string (sql server 2000!) looks like
"data source=DBSERVERNAME;initial catalog=DBNAME;persist security info=True;user id=USERNAME;password=PASSWORD;packet size=4096"
I doubt the connection string is a problem assuming youve used it elsewhere.
Finally have you checked the data types for the columns in the dataset datatable match the ones in the database. In my experience oledb load from excel does not always produce output you might expect, date fields and columns with mixed text and numbers being perticular problems.

Is there a built in class I can use to parse a string containing a MySQL column datatype and return an equivalent .NET Type object?

Is there a built in class I can use to parse a string containing a MySQL column datatype and return an equivalent .NET Type object?
I want to convert some code that reads the column information from a table so that instead of having to pull back a row of data and getting the Schema information from that (using OdbcDataAdapter.FillSchema) - instead the method issues a command that does not do a table scan (hopefully quicker) to get the same info.
Existing code to be replaced:
QueryStr.Append("SELECT * FROM ")
.Append("`" + tableName + "`")
.Append(" LIMIT 1 ");
DataTable dsTable = new DataTable();
using (OdbcConnection DbConn = new OdbcConnection(ConnectionStr))
{
OdbcDataAdapter cmd = new OdbcDataAdapter(QueryStr.ToString(), DbConn);
try
{
cmd.FillSchema(dsTable, SchemaType.Mapped);
QuerySuccessful = true;
}
Attempt at new code:
StringBuilder QueryStr = new StringBuilder();
QueryStr.Append("DESCRIBE ")
.Append("`" + tableName + "`");
DataTable dsTable = new DataTable();
try
{
using (OdbcConnection DbConn = new OdbcConnection(connectionStr))
{
DbConn.Open();
OdbcCommand cmd = new OdbcCommand(QueryStr.ToString(), DbConn);
OdbcDataReader odrColumnReader = cmd.ExecuteReader();
while (odrColumnReader.Read())
{
string strColumnName = odrColumnReader.GetString(0);
string strColumnType = odrColumnReader.GetString(1);
// strColumnType is a string containing the type - e.g. char(6) or whatever
Type type = typeof (string); // TODO replace this bit with a conversion of strColumnType
columns.Add( new SQLcolumn(strColumnName, type, tableName));
}
DbConn.Close();
}
}
The trouble with this is that I get back strColumnType as a string - I want to convert it to a .NET type to match what I got back from FillSchema.
I'd prefer not to code my own conversion method [using this info http://msdn.microsoft.com/en-us/library/cc668763.aspx ] if one exists in the FrameWork / ODBC / ADO.NET.
You can use the OdbcDataReader.GetFieldType method, eg:
Type firstColumnType = odrColumnReader.GetFieldType(0);

Categories

Resources