Get AutoNumber column index in Ms Access 2010/2013 - c#

(first sorry for my English):
I want to temporarily change auto-number column to int64 data type to import records from another database. After importing the records, I want to change it back to auto-number.
My Problem:
I try to use the table.Columns[i].AutoIncrement property to check if this column is auto-number and get its index so that I can change its datatype, but this property didn't work for me, it returned false for all columns.
I work with 2010/2013 Access database.
So I want to know what to do to get index of auto-number column?

You can use this approach
// Bogus query, we don't want any record, so add a always false condition
OleDbCommand cmd = new OleDbCommand("SELECT * FROM aTable where 1=2", con);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
DataTable test = new DataTable();
da.FillSchema(test, SchemaType.Source);
for(int x = 0; x < test.Columns.Count; x++)
{
DataColumn dc = test.Columns[x];
Console.WriteLine("ColName = " + dc.ColumnName +
", at index " + x +
" IsAutoIncrement:" + dc.AutoIncrement);
}

Related

Error with SqlDataAdapter Update

Using C#, SQL Server 2016 - Trying to write a method to update every record in a dataset - a single field to a new value - using a DataAdapter object, and am getting the following error message:
Dynamic SQL generation is not supported against a SelectCommand that does not return any base table information.
Here is my code (a method on a class containing a DataSet TheDS, an SQLDataAdapter TheAdapter, and a DataTable TheDataTable):
public void updateDSField<T>(string fieldName, T newVal)
{
// Updates field in dataset
SqlCommandBuilder builder = new SqlCommandBuilder(TheAdapter);
var col = TheDataTable.Columns[fieldName];
foreach (DataRow row in TheDataTable.Rows) row[col] = newVal;
TheAdapter.UpdateCommand = builder.GetUpdateCommand();
TheAdapter.Update(TheDS);
}
I read something about the SqlCommandBuilder not being able to handle >1000 rows - is that correct? Either way, what is the correct way to perform this operation?
I needed to build my own command string, as the builder does not handle more than 1000 rows. I was worried that this would update the entire table at first, but this link
C# DataTable Update Multiple Lines
put my mind at ease. (Assuming also I know the table name, TheTableName).
public void updateDSField<T>(string fieldName, T newVal)
{
// updates field in dataset
var col = TheDataTable.Columns[fieldName];
foreach (DataRow row in TheDataTable.Rows) row[col] = newVal; // * this marks the rows to be update by the commandtext
// create adapter and update string
TheAdapter.UpdateCommand = TheConn.CreateCommand();
string newValString = newVal.ToString();
if (typeof(T) == typeof(string)) newValString = "'" + newValString + "'";
TheAdapter.UpdateCommand.CommandText = "UPDATE [" + TheTableName + "] SET [" + fieldName + "] =" + newValString;
TheAdapter.Update(TheDS); // this will only update those rows marked by step * above
}

Can I insert the data to a table which columns are unknown in mdb file from c#?

I think I have a weird doubt!!
I have created a table using C#[with a tool not programatically ] in mdb file, then I am inserting the values to that table, what the issue is I don't know how many columns are available in that table, but I wanna insert value from the datagridview..
Spire.DataExport.Access.AccessExport accessExport = new Spire.DataExport.Access.AccessExport();
accessExport.DataSource = Spire.DataExport.Common.ExportSource.DataTable;
accessExport.DataTable = this.dataGridView2.DataSource as System.Data.DataTable;
accessExport.DatabaseName = saveFileDialog1.FileName;
accessExport.TableName = "ExtractedTable";
accessExport.SaveToFile();
//OleDbCommand cmdt = new OleDbCommand("Create Table "+profiletablegrid. ", con);
string strDirectory = saveFileDialog1.FileName;
OleDbConnection conn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + strDirectory);
conn.Open();
for (int i = 41; i < dataGridView2.Rows.Count; i++)
{
for (int j = 0; j < dataGridView2.Rows[i].Cells.Count; j++)
{
OleDbCommand cmdd = new OleDbCommand("Insert into sample values(#a,#b,#c,#d)", conn);
cmdd.Parameters.Add("#a", OleDbType.VarChar).Value = dataGridView2.Rows[i].Cells[j].Value.ToString();
cmdd.Parameters.Add("#b", OleDbType.VarChar).Value = dataGridView2.Rows[i].Cells[j].Value.ToString();
cmdd.Parameters.Add("#c", OleDbType.VarChar).Value = dataGridView2.Rows[i].Cells[j].Value.ToString();
cmdd.Parameters.Add("#d", OleDbType.VarChar).Value = dataGridView2.Rows[i].Cells[j].Value.ToString();
cmdd.ExecuteNonQuery();
}
}
So Since I know the columns I am inserting 4 values, but if I don't know how many columns are there, then how can i insert the value...
I can count the datagridview total columns, but how can I insert according to that?
Without knowing column Names or Number of Columns of a table in my experience it's not possible to insert data in to it. How ever you can use this work around to get column names of particular table then insert data into those columns.
The first thing you would do is make sure that no data gets returned:
SELECT TOP 0 your_table.* FROM your_table WHERE 1 = 2;
Now assuming you know how to set up a DataReader you would do the following:
using(var reader = command.ExecuteReader())
{
// This will return false - we don't care, we just want to make sure the schema table is there.
reader.Read();
var table = reader.GetSchemaTable();
foreach (DataColumn column in table.Columns)
{
Console.WriteLine(column.ColumnName);
}
}
Now you have column names so build up your insert statement.
Ok Consider you have n number of columns then your code will look like this.
List<string> colArr=new List<string>();
foreach (DataColumn column in table.Columns)
{
colArr.Add(column.ColumnName);
}
now build your sql in this way.
string colNames="";
string val="";
for (int i = 0; i < colArr.Count; i++)
{
if(i!=colArr.Count-1)
{
colNames+=col+",";
val+="Some Value,";
}
else
{
colNames+=col;
val+="Some Value";
}
}
string sqlQuery="Insert Into your_Table "+colNames+" ("+val+")";
assuming you are using OleDbConnection you can call
DataTable schema = connection.GetSchema("Columns");
to get the schema data of your Database ... in that table you will find each column of each table in the db ...
use that to build you SQL statement at runtime

How to present the data from multiple DataTables in a series of stacked data grids?

I have an undefined amount of DataTables. I get them from my DataBase, each DataTable stands for one Table in my DataBase, I dont use all Tables of the DataBase just the few I need (these were selectet earlier in the code) and not all columns (same like the tables).
Now my problem: I want to show them in a DataGrid one below the other with breaks between them for the tablename.
This is how i get my DataTables:
List<DBTable> selectedTbl = DBObject.SingDBObj.GetSelectedTables();
foreach (DBTable tbl in selectedTbl)
{
string cols = tbl.GetSelectedColumnNames();
string query = #"SELECT " + cols + " FROM [" + DBObject.SingDBObj.DataSource + "].[" + DBObject.SingDBObj.Database + "].[" + tbl.Schema + "].[" + tbl.Name + "];";
DataTable DTShow = DBObject.SingDBObj.ExecuteQuery(query);
}
dataGridShowColmns.DataContext = ??;
Is there an easy way to do this?
You maybe mean something like:
DataSet ds = new DataSet();
// dataset is here just initialized for demonstration, you would first
// get the tables from database and populate dataset
for (int i = 0; i < ds.Tables.Count; i++)
{
DataTable dt = ds.Tables[i];
foreach (DataRow dr in dt.Rows)
{
dataGridView1.Rows.Add(dr);
}
}
In SQL name to a dataset cannot be assigned, only way you can do it in c#/VB. like
Dataset.Table[0].Name = "MyTable";

Cannot add DataTable into MS Access table

I have a DataTable with about 6000 rows created from a query to SQL Server DB. Now I try to add the data into a MS-Access table. Everything seems to work. No exceptions are raised but no data is a being added. Here is the code I'm using:
DataTable t = new DataTable();
// fill data table
// Create DB - works!
var Name = DateTime.Now.ToString("H_mm_ss");
string strAccessConnectionString = #"Provider = Microsoft.Jet.OLEDB.4.0;" +
#"Data Source=" + "C:\\chhenning\\" + Name + ".mdb;";
ADOX.CatalogClass Catalog = new ADOX.CatalogClass();
Catalog.Create(strAccessConnectionString);
OleDbConnection accessConnection = new OleDbConnection(strAccessConnectionString);
accessConnection.Open();
// Create Table - works!
OleDbCommand Command = accessConnection.CreateCommand();
Command.CommandText = "Create Table Test( "
+ " ID_ int not null "
+ " , Year_ int not null "
+ " , Value_ float not null )";
Command.ExecuteNonQuery();
// Add data into table - does not work!
var adapter = new OleDbDataAdapter();
adapter.SelectCommand = new OleDbCommand("select * from Test", accessConnection);
var cbr = new OleDbCommandBuilder(adapter);
cbr.GetInsertCommand();
var Rows = adapter.Update(t);
I have made sure that my DataTable has data in and that both the DataTable and MS-Access have the same columns with the same data types.
Can someone spot what wrong with code? What are the steps I do to investigate the problem further?
The adapter.Update(table) method works looking at the RowState of the rows in the DataTable.
If the rows have RowState == DataRowState.Unchanged, the method will not perform any update.
I suppose that you load the datatable from the SqlServer database without making any change and thus the RowState is Unchanged for every row. Try to loop on the Rows and call
foreach(DataRow r in t.Rows)
r.SetAdded();
This will force the RowState on each column to Added and then the InsertCommand on the DataAdapter will execute the insert

How to query from SQL comparing with array members?

So I have an array containing computer names called hostnames[].
Contains: compname1, compname2, compname3 etc.
Actually it gets it's members from another SQL query.
I have a data table and I need to query all rows where hostname column has any of the computer names in my array.
something like:
select * from table where hostname in hostnames[]
How should I proceed to achieve my goal?
EDIT:
I was thinking on the below:
string temp = "'" + hostnames[0] + "'";
for(int i=1; i<hostnames[].Lenght; i++)
{
temp = temp + ",'" + hostnames[i] + "'";
}
string query = "SELECT * FROM table WHERE hostname IN (" + temp + ")";
The best way to use parameters for an IN clause is to use Table-valued parameters, in your case you will need a type as a table with one nvarchar column. I've used a generic name so the type can be reused without confusion:
CREATE TYPE dbo.StringList AS TABLE (value NVARCHAR(MAX));
Then it is simply a case of adding your values to a DataTable and passing this as a parameter to your select command:
var dataTable = new DataTable();
dataTable.Columns.Add(new DataColumn("Value", typeof(string)));
for (int i = 0; i < hostnames.Length; i++)
{
var dr = dataTable.NewRow();
dr[0] = "";
dataTable.Rows.Add(dr);
}
using (var connection = new SqlConnection("connectionString"))
using (var command = new SqlCommand("SELECT * FROM Table WHERE HostName IN (SELECT Value FROM #StringList)", connection))
{
SqlParameter stringListParameter = new SqlParameter("#StringList", SqlDbType.Structured);
stringListParameter.Value = dataTable;
stringListParameter.TypeName = "dbo.StringList";
command.Parameters.Add(stringListParameter);
// OPEN CONNECTION EXECUTE COMMAND ETC
}
There are 4 ways to achieve what you want. You choose what works best for you.
Use IN as in your code
Break down to OR. A IN (1, 2, 3) => A=1 OR A=2 OR A=3
Use Table Valued Parameters
User the sql query passed earlier. ex: "SELECT * FROM table WHERE hostname IN (Select hostname from tableusedEarlier)"

Categories