Use OleDbDataAdapter to insert into an Access db - c#

I would like to insert some data into an Access Database.
DataTable dt = new DataTable();
String sql = string.Format("SELECT * FROM {0} where 1=0; ", tmap.SqlTableName);
string con = string.Format(conn, accessPath);
OleDbDataAdapter da = new OleDbDataAdapter(sql, con);
OleDbCommandBuilder cmdBuilder = new OleDbCommandBuilder(da);
da.InsertCommand = cmdBuilder.GetInsertCommand(true); // Returns "INSERT INTO test (int, bdate, amt, text, bit) VALUES (?, ?, ?, ?, ?)"
da.Fill(dt);
//Add data to the DateTable
for (int i = 0; i < rowCount; i++)
{
DataRow dr = dt.NewRow();
//....
dt.Rows.Add(dr);
}
da.Update(dt); //This is where things go south.
System.Data.OleDb.OleDbException
Message: Syntax error in INSERT INTO statement.
Source: Microsoft JET Database Engine.
If I change the insert command:
da.InsertCommand = new OleDbCommand("INSERT INTO test ([text]) VALUES (?)");
and change the incoming data to only have a single text value I get:
No value given for one or more required parameters.
Am I missing something?

The issue was in the data types. The code in the question works if the data types are compatible.

Make sure all required columns are included in the insert query.
If It doesn't work then create a new method for inserting and follow this:
OleDbConnection conn = new OleDbConnection (connectionString);
OleDbCommand command = new OleDbCommand();
command.Connection = conn;
command.CommandText= "INSERT INTO myTable (col1, col2) VALUES (#p_col1, #p_col2)";
command.Parameters.Add ("#p_col1", OleDbType.String).Value = textBox1.Text;
...
command.ExecuteNonQUery();

Related

How to query two access database(accdb) files that have different schema?

I need your help.
Suppose there are two access database(accdb) files which have some columns with same names but some are not. For example:
start
Then how to make a query to both database at the same time?
OleDbConnection Conn = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=..\\DATABASE_A.accdb;");
OleDbCommand command = new OleDbCommand();
OleDbDataAdapter adapter = new OleDbDataAdapter();
DataTable dt = new DataTable();
Con.Open();
string query = "Select [JOB],[DATE] From TABLE_A WHERE [NAME] = ?";
command.CommandText = query;
command.Parameters.AddWithValue("#NAME", $someDate);
command.Connection = Conn;
adapter.SelectCommand = command;
adapter.Fill(dt);
Conn.Close();
However, how about DATABASE_B.accdb to fill the same DataTable dt but TABLE_B's column has different name?I want to form a datatable like that:
result
Thanks for any suggestion.
In SQL you would use a union query.
In C# you could use LINQ Union.

How does sanitize the sql parameter

I write these code all are working fine but there is a warning coming that sanitize the sql parameter.
private DataSet ExcelToDataSet(string fileData)
{
DataSet ds = new DataSet();
string connectionString = GetConnectionString(fileData);
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
// Get all Sheets in Excel File
DataTable dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
// Loop through all Sheets to get data
foreach (DataRow dr in dtSheet.Rows)
{
string sheetName = dr["TABLE_NAME"].ToString();
if (!sheetName.EndsWith("$"))
continue;
// Get all rows from the Sheet
cmd.CommandText = "SELECT * FROM [" + sheetName + "]";
DataTable dt = new DataTable();
dt.TableName = sheetName;
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(dt);
ds.Tables.Add(dt);
}
cmd = null;
conn.Close();
}
return (ds);
}
I have to sanitize the following line
cmd.CommandText = "SELECT * FROM [" + sheetName + "]";
Usually, when writing SQL Statements, you need to use parameters to pass the data from user input into the sql statement, to prevent SQL Injection attacks. That's why you get this warning. However, there is nothing you can do about it since it's impossible to parameterize identifiers in SQL, and you don't need to do it because you are not concatenating user input, and you are not running this query on a database, so even if you could use SQL injection, the worst you can do is corrupt a single file
UPDATE: I did not notice this was a OleDbConnection, the database you are connecting to may not have the same functionality to quote an identifier. I am leaving this answer here in case someone comes across this question and needs the same thing but for a SQL connection.
As the others have said, there is no need to worry about the warning in this case as the data is not coming from user data.
However everyone is wrong about the fact you cannot parameterize an identifier. You need to build the query dynamically server side and use the QUOTENAME function but it is possible.
foreach (DataRow dr in dtSheet.Rows)
{
string sheetName = dr["TABLE_NAME"].ToString();
if (!sheetName.EndsWith("$"))
continue;
// Get all rows from the Sheet
cmd.CommandText = #"
declare #sql nvarchar(114);
set #sql = N'select * from ' + quotename(#sheetname)
exec sp_executesql #sql
";
cmd.Parameters.Clear();
cmd.Parameters.Add("#sheetname", SqlDbType.NVarChar, 100).Value = sheetName;
DataTable dt = new DataTable();
dt.TableName = sheetName;
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(dt);
ds.Tables.Add(dt);
}
This will generate a dynamic query that will safely escape the name of the table.

How to insert a datatable to an access database in C#

I have 2 table in an access database
now I want to select from one table and insert them into another one.
this is my code but it shows an exception in line Cmd.ExecuteNonQuery();
{"Syntax error (missing operator) in query expression 'System.Object[]'."}
the code is :
public static void SetSelectedFeedIntoDB(Form2 frm2)
{
string StrCon = System.Configuration.ConfigurationManager.ConnectionStrings["FeedLibraryConnectionString"].ConnectionString;
OleDbConnection Connection = new OleDbConnection(StrCon);
OleDbDataAdapter DataA = new OleDbDataAdapter("Select * from FeedLibrary where ID=" + frm2.FeedSelectListBox.SelectedValue, Connection);
DataTable DTable = new DataTable();
DataA.Fill(DTable);
OleDbCommand Cmd = new OleDbCommand();
Cmd.Connection = Connection;
Connection.Open();
foreach (DataRow DR in DTable.Rows)
{
Cmd.CommandText = "insert into SelectedFeeds Values(" + DR.ItemArray + ")";
Cmd.ExecuteNonQuery();
}
Connection.Close();
}
what should I do to fix this?
Your error is caused by the fact that you are concatenating the ItemArray property of a DataRow to a string. In this case the ItemArray (that is an instance of an object[]) has no method that automatically produces a string from its values and thus returns the class name as a string "object[]" but of course this produces the meaningless sql string
"insert into SelectedFeeds Values(object[])";
But you could simply build a SELECT .... INTO statement that will do everything for you without using DataTables and Adapters
string cmdText = #"SELECT FeedLibrary.* INTO [SelectedFeeds]
FROM FeedLibrary
where ID=#id";
using(OleDbConnection Connection = new OleDbConnection(StrCon))
using(OleDbCommand cmd = new OleDbCommand(cmdText, Connection))
{
Connection.Open();
cmd.Parameters.Add("#id", OleDbType.Integer).Value = Convert.ToInt32( frm2.FeedSelectListBox.SelectedValue);
cmd.ExecuteNonQuery();
}
However, the SELECT ... INTO statement creates the target table but gives error if the target table already exists. To solve this problem we need to discover if the target exists. If it doesn't exist we use the first SELECT ... INTO query, otherwise we use a INSERT INTO ..... SELECT
// First query, this creates the target SelectedFeeds but fail if it exists
string createText = #"SELECT FeedLibrary.* INTO [SelectedFeeds]
FROM FeedLibrary
where ID=#id";
// Second query, it appends to SelectedFeeds but it should exists
string appendText = #"INSERT INTO SelectedFeeds
SELECT * FROM FeedLibrary
WHERE FeedLibrary.ID=#id";
using(OleDbConnection Connection = new OleDbConnection(StrCon))
using(OleDbCommand cmd = new OleDbCommand("", Connection))
{
Connection.Open();
// Get info about the SelectedFeeds table....
var schema = Connection.GetSchema("Tables",
new string[] { null, null, "SelectedFeeds", null});
// Choose which command to execute....
cmd.CommandText = schema.Rows.Count > 0 ? appendText : createText;
// Parameter #id is the same for both queries
cmd.Parameters.Add("#id", OleDbType.Integer).Value = Convert.ToInt32( frm2.FeedSelectListBox.SelectedValue);
cmd.ExecuteNonQuery();
}
Here we have two different queries, the first one create the SelectedFeeds table as before, the second one appends into that table.
To discover if the target table has already been created I call Connection.GetSchema to retrieve a datatable (schema) where there is a row if the table SelectedFeeds exists or no row if there is no such table.
At this point I set the OleDbCommand with the correct statement to execute.

Access Database error:: “No value given for one or more required parameters.”

I have a datagridview. In this DGV first colum is a combobox column. I want to make, when this combobox value is selected next fild will be filled automatically from database. But there shows a error.
No value given for one or more required parameters on
OleDbDataReader dr1 = cmd1.ExecuteReader();
I post the code. Please help me.
OleDbConnection con = new OleDbConnection(conn);
con.Open();
for (int i = 0; i < dgv.Rows.Count; i++)
{
string query = "select Description from General where AccCode='" +
dgv.Rows[i].Cells[0].Value +
"' and conpanyID='" +
label1.Text + "'";
OleDbCommand cmd1 = new OleDbCommand(query, con);
//OleDbDataAdapter daBranchName = new OleDbDataAdapter(cmd);
OleDbDataReader dr1 = cmd1.ExecuteReader();
while (dr1.Read())
{
dgv.Rows[i].Cells[1].Value = dr1["Description"].ToString();
}
}
con.Close();
This kind of string concatenations are open for SQL Injection attacks.
Use parameterized queries instead.
string query = "select [Description] from [General] where AccCode= ? and conpanyID= ?";
OleDbCommand cmd1 = new OleDbCommand(query, con);
cmd1.Parameters.AddWithValue("#acc", dgv.Rows[i].Cells[0].Value);
cmd1.Parameters.AddWithValue("#ID", label1.Text);
As HansUp pointed, Description and General are reserved keywords. Use them with square brackets like [Description] and [General]
As suggested, use parameterized queries.
As far as the error is concerned, I'm guessing this field name is wrong:
conpanyID=
should be:
companyID=
Use Parameters, otherwise it will open for sql injection attacks.
string query = "select [Description] from General where AccCode=? and conpanyID=?";
now you can set parameters
cmd.Parameters.AddWithValue("#p1", val1);
cmd.Parameters.AddWithValue("#p2", val2);

Insert new DataRow with autoincrement Primary Key with C# (OleDB)

I' m trying to insert a new DataRow (locally stored in a DataSet) to a Access table with C#. The table is also created by this app and has 3 columns:
ID (integer, primary key, Required is set to No though I've set it as primary key)
Name (string)
Money (int)
My current code looks like that:
OleDbConnection con = new OleDbConnection();
OleDbCommand cmd = new OleDbCommand();
OleDbDataAdapter da;
DataSet ds = new DataSet();
DataView dv = new DataView();
DataRow row;
string Con = #"Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=";
string path = "V:\\ProjectProgress\\Test.mdb";
con.ConnectionString = Con + path;
if (con.State == ConnectionState.Closed)
{
con.Open();
}
cmd.Connection = con;
cmd.CommandText = "SELECT ID, Name, Money FROM Test";
da = new OleDbDataAdapter(cmd);
da.TableMappings.Add("Table", "Test");
da.Fill(ds, "Test");
ds.Tables["Test"].Columns[0].AutoIncrement = true;
ds.Tables["Test"].Columns[0].AutoIncrementSeed = -1;
ds.Tables["Test"].Columns[0].AutoIncrementStep = -1;
dv.Table = ds.Tables["Test"];
row = ds.Tables["Test"].NewRow();
row["Name"] = "Huber";
row["Money"] = 100;
ds.Tables["Test"].Rows.Add(row);
string strOLE = "INSERT INTO Test ([Name], [Money]) Values(#Name, #Money)";
OleDbCommand cmdi = new OleDbCommand(strOLE, con);
cmdi.Parameters.Add("#Name", OleDbType.VarChar, 25, "Name");
cmdi.Parameters.Add("#Money", OleDbType.Integer, 4, "Money");
da.InsertCommand = cmdi;
da.Update(ds.Tables["Test"]);
con.Close();
When updating I'm always getting a
Index or primary key cannot contain a Null value
error.
Setting the Required value of the ID column to Yes, will throw a
Index or Primary Key Cannot Contain a Null Value
error.
How can I let Access assign the right primary key and how do I get the new value back into my dataset?
Using SCOPE_IDENTITY() is not possible in Access as far as I know and found in some forums.
(Working with Visual C# Express 2010, Access 2003)
The following is complete working test code to illustrate the procedure. All we need to do is provide an OleDbDataAdapter.SelectCommand that includes the primary key and the columns we want to update, and the OleDbCommandBuilder object will create the INSERT statement for us:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.OleDb;
namespace oleDbTest
{
class Program
{
static void Main(string[] args)
{
string myConnectionString;
myConnectionString =
#"Provider=Microsoft.ACE.OLEDB.12.0;" +
#"Data Source=C:\Users\Public\Database1.accdb;";
using (OleDbConnection con = new OleDbConnection())
{
con.ConnectionString = myConnectionString;
con.Open();
using (OleDbDataAdapter da = new OleDbDataAdapter())
using (OleDbCommandBuilder bld = new OleDbCommandBuilder(da))
{
bld.QuotePrefix = "["; // these are
bld.QuoteSuffix = "]"; // important!
da.SelectCommand = new OleDbCommand(
"SELECT [ID], [Name], [Money] " +
"FROM [Test] " +
"WHERE False",
con);
using (System.Data.DataTable dt = new System.Data.DataTable("Test"))
{
// create an empty DataTable with the correct structure
da.Fill(dt);
System.Data.DataRow dr = dt.NewRow();
dr["Name"] = "Huber";
dr["Money"] = 100;
dt.Rows.Add(dr);
da.Update(dt); // write new row back to database
}
}
con.Close();
}
Console.WriteLine();
Console.WriteLine("Done.");
}
}
}
My first thought is that your problem might be that both AutoIncrementSeed and AutoIncrementStep are set to a negative value of -1. Try setting both to a positive value.
[EDIT]
Second thought, you might want to try the OleDbCommandBuilder (MSDN documentation here). It creates your INSERT, UPDATE, and DELETE statements automatically using the column information of your DataSet.
At my former employer we used OleDbCommandBuilder all the time when working with Access and it worked like a charm, even with auto increment fields.

Categories