I want to get the structure of all the tables and odbc-Datasources in an Access database with C#. So I tried this code:
string text="";
var tables = GetApp().CurrentData.AllTables;
for (int i = 0; i < tables.Count; i++)
{
var currentTable = tables.Item(i);
text = text + currentTable.FullName + Environment.NewLine;
}
MessageBox.Show(text);
This returns all the availible tablenames. But how do I get the columnnamens and types of the tables?
I tried this:
var props = currentTable.Properties;
for (int j = 0; j < props.Count; j++)
{
var prop = props.Item(j);
text = text + Environment.NewLine + prop.Name;
}
but it didnt work (An exception was thrown when I accessed the properties).
I tried to use a oleDB connection + GetSchema to get the table structure. But with this method I only received the "native" (or local) tables inside of the access-db. But there are also some ODBC-Linked-Tables which I am also interested.
So how is it possible to get the TableNames, ColumnNames and Columntypes in an ms-access database file?
You need to use CurrentDb().TableDefs if you want to access table columns. The AllTables collection doesn't offer access to the table fields.
CurrentDb().TableDefs[0].Fields[0].Name should return the name of the first column of the first table, for example.
Related
I'm writing an upgrade program for moving Access 2.0 .mdb files to Access 2003 .mdb. We are staying with the mdb file structure for a couple of reasons as this is code that is in several customers locations, and the mdb allows us to utilize existing code.
The main problem:
I go through JET to read in the tables from the file.mdb and read each table into a C# datatable. I then do several checks and duplicate the table in the 2003 mdb db. I use the DataTable.PrimaryKey function to gather the columns that are primary key columns, but I don't get reliable results.
Access 2.0 shows the PrimaryKey in several tables (single column) where DataTable does not, but not always.
I have verified that I do get the PrimaryKey(s) on some tables, just not all.
DataColumn[] dcPrimaryKeyCols = OrgTbl.PrimaryKey;
//Read the Ordinal so we can order the columns correctly
for (int m = 0; m < NumCols; m++)
{
ColumnOrder[m] = OrgTbl.Columns[m].Ordinal;
if (ColumnOrder[m] != m)
MessageBox.Show("In table " + nm+ "out of order ordinal on column: " + OrgTbl.Columns[m].ColumnName);
}
lblStatus.Text = "Creating Table";
pbTableProgress.Value = 0;
pbTableProgress.Maximum = NumCols;
for (int col = 0; col < NumCols;col++ )
{
pbTableProgress.Value = col;
Application.DoEvents();
sColNm=OrgTbl.Columns[col].ColumnName.Trim();
bPrimaryKey = false;
//determine if this column is part of a primary key group
for (int k = 0; k < dcPrimaryKeyCols.Length;k++ )
{
if (dcPrimaryKeyCols[k].ColumnName.Trim().Equals(sColNm))
{
bPrimaryKey = true;
break;
}
}
I have set a breakpoint in the bPrimaryKey = true line, and it gets there sometimes, but not on all the tables where a primarykey is defined.
One thing I noted, in Access Ver 2.0, the column information for the some of the primary keys show: required = no, unique = no. I don't know if this causes JET or the C# datatable to unmark a primarykey column or if other things are at work here. But the end results is that I am not able to correctly detect ALL primarykey columns.
On my pc (Win7) the statement is running without error. If I copy the c# .exe to a server (Win2012 server) where the program should finally run then I get the error
ORA-01843: not a valid month
I read a csv-file and insert it into a oracle-db with the statement
command.CommandText = "INSERT INTO table (DATUM, ...) VALUES('" + dr[0].ToString() + "',..."')";
dr[0].ToString() has the value "01.06.2016"
The column DATUM is type DATE in the oracle-db.
I debugged the code with a messagebox and get this result:
I can't see any difference between those two statements, the left one from the server is calling the error when I execute int rowsupdated = command.ExecuteNonQuery();
I already compared the region settings and they are the same (german) on both systems. What else could cause the problem? Thanks
Part for filling the Datatable (source for dr):
StreamReader oStreamReader = new StreamReader(Zielverzeichnis + Dateiname, System.Text.Encoding.UTF8); //nach, für Umlaute
DataTable dtCSV_Import = null;
int RowCount = 0;
string[] ColumnNames = null;
string[] oStreamDataValues = null;
//using while loop read the stream data till end
while (!oStreamReader.EndOfStream)
{
String oStreamRowData = oStreamReader.ReadLine().Trim();
if (oStreamRowData.Length > 0)
{
oStreamDataValues = oStreamRowData.Split(';');
//Bcoz the first row contains column names, we will poluate
//the column name by
//reading the first row and RowCount-0 will be true only once
if (RowCount == 0)
{
RowCount = 1;
ColumnNames = oStreamRowData.Split(';');
dtCSV_Import = new DataTable();
//using foreach looping through all the column names
foreach (string csvcolumn in ColumnNames)
{
DataColumn oDataColumn = new DataColumn(csvcolumn.ToUpper(), typeof(string));
//setting the default value of empty.string to newly created column
oDataColumn.DefaultValue = string.Empty;
//adding the newly created column to the table
dtCSV_Import.Columns.Add(oDataColumn);
}
}
else
{
//creates a new DataRow with the same schema as of the oDataTable
DataRow oDataRow = dtCSV_Import.NewRow();
//using foreach looping through all the column names
//Prüfen was kleiner ist, Spalten aus XML oder tatsächliche Spalten in der CSV -> sonst Fehler [i]
if (oStreamDataValues.Length < ColumnNames.Length)
{
for (int i = 0; i < oStreamDataValues.Length; i++)
{
oDataRow[ColumnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
}
}
else
{
for (int i = 0; i < ColumnNames.Length; i++)
{
oDataRow[ColumnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
}
}
//adding the newly created row with data to the oDataTable
dtCSV_Import.Rows.Add(oDataRow);
}
}
}
//close the oStreamReader object
oStreamReader.Close();
//release all the resources used by the oStreamReader object
oStreamReader.Dispose();
If you are inserting values into a date column and try to insert a string value then Oracle will implicitly call TO_DATE() using the NLS_DATE_FORMAT session parameter as the format mask. If this format mask does not match then you will get an exception.
Session parameters can be set by individual users within their sessions - so if user Alice has the expected parameters this does not mean that user Bob will have the same parameters and the identical query you are using will not work as you are relying on implicitly casting values. Or even worse, Bob has the expected parameters today and then tomorrow decided that he would prefer his dates formatted as DD-MON-YYYY and changes his NLS_DATE_FORMAT and suddenly, without changing your code, everything breaks and you are going to have a very bad time debugging the error.
If you want to insert a date then either:
Pass it as a bind variable (the best option) without converting it to a string; or
Use date literals (i.e. DATE '2016-06-01'); or
Use TO_DATE() with a specified format mask (i.e. TO_DATE( '" + dr[0].ToString() + "', 'DD.MM.YYYY' )).
You can read about bind variables in the Oracle Documentation or in this SO question.
I've been trying to get an access tables names in c#, using:
m_cnADONewConnection.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=test.mdb";
m_cnADONewConnection.Open();
DataTable userTables = m_cnADONewConnection.GetSchema("Tables");
But don't know how to show only the tables names...any help?
// Add list of table names to string list
List<string> names = new List<string>();
for (int i=0; i < userTables.Rows.Count; i++)
names.Add(userTables.Rows[i][2].ToString());
I took this from a similar question.
I'm trying to fetch data from multiple tables from an Oracle db and insert it into a sql db. The problem that I am running into is that I am fetching almost 50 columns of data all of different datatypes. I then proceed to insert these individual column values into a SQL statement which then inserts the data into the sql db. So the algo looks something like this:
Fetch row data{
create a variable for each individual column value ( int value = reader.getInt32(0); )
add a sqlparameter for it (command.Parameters.Add(new SqlParameter("value", value)); )
once all the 50 or so variables have been created make a sql statement
Insert into asdf values (value,........)
}
Doing it this way for a table with <10 columns seems ok but when it exceeds that length this process seems tedious and extraneous. I was wondering if there was a simpler way of doing this like fetch row data and automatically determine column data type and automatically create a varialbe and automatically insert into sql statement. I would appreciate it if anyone could direct me to the right way of doing this.
The data reader has a neutral GetValue method returning an object and the SqlCommand has an AddWithValue method that does not require to specify a parameter type.
for (int i = 0; i < reader.VisibleFieldCount; i++) {
object value = reader.GetValue(i);
command.Parameters.AddWithValue("#" + i, value);
}
You could also create the SQL command automatically
var columns = new StringBuilder();
var values = new StringBuilder();
for (int i = 0; i < reader.VisibleFieldCount; i++) {
values.Append("#").Append(i).Append(", ");
columns.Append("[").Append(reader.GetName(i)).Append("], ");
}
values.Length -= 2; // Remove last ", "
columns.Length -= 2;
string insert = String.Format("INSERT INTO myTable ({0}) VALUES ({1})",
columns.ToString(), values.ToString());
I have a function which will return multiple ItemIDs as
for (int i = 0; i < dt.Rows.Count; i++)
{
ItemID = int.Parse(dt.Rows[i]["item_Id"].ToString());
dtAtlr = prodctsDCCls.getItemIds(ItemID);
//dtItems = dtAtlr.Copy();
}
I want to keep on searching for all ItemIds from the same table and have to save all the data in one datatable.If I copy one datatable to another datatable, that is replacing the previous datatable. but I need all the data. Please anybody help me
Use DataTable.Merge to merge two data tables. So your code would be:
for (int i = 0; i < dt.Rows.Count; i++)
{
ItemID = int.Parse(dt.Rows[i]["item_Id"].ToString());
dtAtlr.Merge(prodctsDCCls.getItemIds(ItemID)); // For Merging
}
By using DataTable.Copy, your datatable dtAtlr will have the last returned DataTable against the ItemID
You can check DataTable.Merge
Merge the specified DataTable with the current DataTable.