When several fields in a MSAccess table need to be updated (For instance Salary=Salary*Factor, SomeNumber=GetMyBusinessRuleOn(SomeNumber) etc...),and the update should affect every record in a table, which technique would you use?
I have just started to implement this with DataSets, but got stuck (Updating and persisting dataset problem)
But maybe this isn't even the ideal way to handle this kind of batch update?
Note : the updates don't have to be on disconnected data first, so a dataset is not necessary.
UPDATE :
One command won't do, I need some kind of recordset or cursor to cycle through the records
I would just use a ODBCConnection/ODBCCommand and use a SQL Update query.
There is a JET Database driver that you should be able to use to establish a database connection to a MSAccess database using the ODBCConeection object.
string connectionString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=c:\\PathTo\\Your_Database_Name.mdb; User Id=admin; Password=";
using (OdbcConnection connection =
new OdbcConnection(connectionString))
{
// Suppose you wanted to update the Salary column in a table
// called Employees
string sqlQuery = "UPDATE Employees SET Salary = Salary * Factor";
OdbcCommand command = new OdbcCommand(sqlQuery, connection);
try
{
connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
// The connection is automatically closed when the
// code exits the using block.
}
You could use these websites to help you generate a connection string:
http://www.connectionstrings.com/
http://www.sqlstrings.com/
EDIT - Example for using a data reader to cycle through records in order to aply the business rule
I should note that the following example could be improved in certain ways (especially if the database driver supports parameterized queries). I only wanted to give a relatively simple example to illustrate the concept.
using (OdbcConnection connection =
new OdbcConnection(connectionString))
{
int someNumber;
int employeeID;
OdbcDataReader dr = null;
OdbcCommand selCmd = new OdbcCommand("SELECT EmployeeID, SomeNumber FROM Employees", connection);
OdbcCommand updateCmd = new OdbcCommand("", connection);
try
{
connection.Open();
dr = selCmd.ExecuteReader();
while(dr.Read())
{
employeeID = (int)dr[0];
someNumber = (int)dr[1];
updateCmd.CommandText = "UPDATE Employees SET SomeNumber= " + GetBusinessRule(someNumber) + " WHERE employeeID = " + employeeID;
updateCmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// Don't forget to close the reader when we're done
if(dr != null)
dr.Close();
}
// The connection is automatically closed when the
// code exits the using block.
}
Sounds like you just need an update statement:
http://msdn.microsoft.com/en-us/library/bb221186.aspx
You can use the OleDb Provider for this.
Related
I'm having problems with updating a row in the Users table of my Access DB. Here is the code below:
private void SaveProfileInfo()
{
try
{
ChangeForeColorOfStatusMsg(Color.Black);
ChangeTextOfStatusMsg("Saving new profile information...");
const string cmd = #"UPDATE Users SET LastName=#LastName,FirstName=#FirstName,MiddleName=#MiddleName,Add_Num=#Add_Num,Add_Street=#Add_Street,Add_Brgy=#Add_Brgy,Add_City=#Add_City,MobileNumber=#MobileNumber,Gender=#Gender WHERE ID=#ID;";
var dbConn = new OleDbConnection(cs);
var dbCmd = new OleDbCommand(cmd, dbConn);
dbCmd.Parameters.AddWithValue("#ID", UserLoggedIn.ID);
dbCmd.Parameters.AddWithValue("#LastName", txtLastName.Text);
dbCmd.Parameters.AddWithValue("#FirstName", txtFirstName.Text);
dbCmd.Parameters.AddWithValue("#MiddleName", txtMiddleName.Text);
dbCmd.Parameters.AddWithValue("#Add_Num", txtUnitNum.Text);
dbCmd.Parameters.AddWithValue("#Add_Street", txtStreet.Text);
dbCmd.Parameters.AddWithValue("#Add_Brgy", GetBrgySelectedItem());
dbCmd.Parameters.AddWithValue("#Add_City", GetCitySelectedItem());
dbCmd.Parameters.AddWithValue("#MobileNumber", txtMobileNumber.Text);
dbCmd.Parameters.AddWithValue("#Gender", GetGenderSelectedItem());
dbConn.Open();
dbCmd.ExecuteNonQuery();
dbConn.Close();
ChangeForeColorOfStatusMsg(Color.MediumSeaGreen);
ChangeTextOfStatusMsg("All changes have been saved! This window will close itself after two seconds.");
Thread.Sleep(2000);
CloseForm();
}
catch (Exception)
{
ChangeForeColorOfStatusMsg(Color.Crimson);
ChangeTextOfStatusMsg("Something went wrong while we were connecting to our database. Please try again later.");
hasFinishedEditting = false;
}
}
This method will be done on a separate thread, when the user updates his profile information.
UserLoggedIn is actually a field of a User class (a class that defines a row in my table), which stores all the info of the user who's currently logged in.
When I run this, it does not produce any exceptions or errors. But when I check my table, the values are not updated.
I copy-pasted these codes from the registration form (which works) that I made with this system, and modified it into an UPDATE cmd than an INSERT cmd.
I also made Change Username and Password Forms that use the same cmd as shown below:
public void ChangePass()
{
try
{
ChangeForeColorOfMsg(Color.Silver);
ChangeTextOfMsg("Changing password...");
const string cmd = "update Users set Pass=#Pass where ID=#ID";
var dbConn = new OleDbConnection(cs);
var dbCmd = new OleDbCommand(cmd, dbConn);
dbCmd.Parameters.AddWithValue("#Pass", txtNewPass.Text);
dbCmd.Parameters.AddWithValue("#ID", UserLoggedIn.ID);
dbConn.Open();
dbCmd.ExecuteNonQuery();
dbConn.Close();
ChangeTextOfMsg("Password successfully changed!");
}
catch (Exception)
{
ChangeForeColorOfMsg(Color.Silver);
ChangeTextOfMsg("A problem occurred. Please try again later.");
}
}
And these codes work for me. So I'm really confused right now as to why this update cmd for the profile information isn't working... Is there something I'm not seeing here?
OleDb cannot recognize parameters by their name. It follows a strictly positional order when sending them to your database for updates. In your code above the first parameter is the #ID but this parameter is used last in your query. Thus everything is messed up.
You just need to move the add of the #ID parameter as last in the collection
As a side note, you should be very careful with AddWithValue. It is an handy shortcut, but it has a dark side that could result in wrong queries.
Take a look at
Can we stop using AddWithValue already?
I am creating winform application that have DataGrigView to present a table.
I have a DAL class that is responsible to work with DB.
There are one method that loads data of the table:
public static void GetItemsByOrder(int orderId, ref DataSet dataSet)
{
string queryString = #"Select Id,OrderId as [מס' הזמנה],ItemCode as[מק""ט], ItemName as [שם פריט], ReceiptDate as [ת. הספקה],
WarrantyExpDate as [באחריות עד],SuppliersItemCode as [מק""ט ספק], Supplier as [ספק], Count as[כמות], Active
FROM OrdersManager_Items where OrderId = #param";
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("#param", orderId);
SqlDataAdapter adapter = new SqlDataAdapter(command);
try
{
lock (myLock)
{
adapter.Fill(dataSet,"Items");
}
}
catch (Exception ex)
{
LogWriter.WriteLogEntry(LogWriter.LogType.ERROR, string.Format("Failed to get Items by OrderId code from DB."+
"This is due to exception: {0},\n StackTrace: {1}. ", ex.Message, ex.StackTrace));
dataSet = null;
}
}
And second method that is responsible to update the DB with the changes that were made in the table:
public static bool UpdateItemsByOrder(int orderId, DataSet data)
{
string queryString = #"Select Id,OrderId as [מס' הזמנה],ItemCode as[מק""ט], ItemName as [שם פריט], ReceiptDate as [ת. הספקה],
WarrantyExpDate as [באחריות עד],SuppliersItemCode as [מק""ט ספק], Supplier as [ספק], Count as[כמות], Active
FROM OrdersManager_Items where OrderId = #param";
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("#param", orderId);
SqlDataAdapter adapter = new SqlDataAdapter(command);
try
{
lock (myLock)
{
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
int rowsUpdated = adapter.Update(data,"Items");
return true;
}
}
catch (Exception ex)
{
LogWriter.WriteLogEntry(LogWriter.LogType.ERROR, string.Format("Failed to update Items table in DB. This is due to exception: {0},\n StackTrace: {1}. ", ex.Message, ex.StackTrace));
return false;
}
}
The problem:
If in the Items table new rows were aded or deleted - UpdateItemsByOrder add/delete the rows in the DB as expected.
But updates in existing rows of the Items table does not updated in DB.
There are no error or exceptions.
I have tryed to add builder.GetUpdateCommand() command = no result.
I will be happy to get any help or advice. Thanks
P>S> I am using this MSDN LINK to learn how to work with SQLAdapter
Ok, with the advice of sallushan I got the solution:
The reason why DataAdapter doesn't updated the DB is that updated rows in DataTable has RowState value "Unchanged" instead "Modified".
There is 2 basic ways to resolve this problem:
Update the data direcrly in DataTable and not in DGV
Call DataTable.Rows[indexOfUpdatedRowInDGV].EndEdit() method, after making updates through DGV, as described Here.
Thanks to all for a help :-)
You do realize that you run a SELECT command instead of update right?
My guess is adapter.Update just does select and then reports that no lines where updated since none were.
What I need to do is basically take the users name (which is already stored as a variable) and their score (which is also a variable) and store it in my database when they press 'submit'. Here is the code I have for the button click.
private void btnSubmitScore_Click(object sender, EventArgs e)
{
string connStr = "server=server; " +
"database=databasename; " +
"uid=username; " +
"pwd=password;";
MySqlConnection myConn = new MySqlConnection(connStr);
}
Obviously i have changed the login details etc. I have had a look around and have only managed to find confusing codes about how to display data from a database in a form (i will do this later), but for now, i need to know how to add sName and iTotalScore into the database. (Fields are called 'Name' and 'Score' in DB)
You are going to use a combination of SqlConnection, SqlCommand and their properties. the connection is essentially the stuff of your code. The command is a literal SQL statement, or a call to a stored procedure.
A common C# idiom is to form your code around the very first line as shown here:
using (SqlConnection myConnection = new SqlConnection()) {
string doThis = "select this, that from someTable where this is not null";
SqlCommand myCommand = new SqlCommand(dothis, myConnection);
try {
myCommand.Connection.Open();
myReader = myCommand.ExecuteReader(); //pretend "myReader" was declared earlier
} catch (Exception myEx) {
// left to your imagination, and googling.
}
finally {
myCommand.Connection.Close();
}
}
// do something with the results. Your's to google and figure out
The general outline is
Using a connection
instantiate and configure an SqlCommand
Use try/catch as shown.
The "using" block gives use behind the scenes cleanup/disposal of all those objects we don't need anymore when we're done; in particular the SqlConnection object.
You must learn more about these Sqlxxxxx classes, there's lots of ways to configure them to do what you want.
I am not familiar with the MySql connector, but the code should be something along the lines of:
private void Insert()
{
string connStr = "server=server; " +
"database=databasename; " +
"uid=username; " +
"pwd=password;";
string query = "INSERT INTO TableName('Name','Score) VALUES (#name, #score);";
using(MySqlConnection connection = new MySqlConnection(connStr))
{
MySqlCommand insertCommand = new MySqlCommand(connection,command);
insertCommand.Paramaters.AddWithValue("#name",sName);
insertCommand.Paramaters.AddWithValue("#score",iTotalScore);
connection.Open();
command.ExecuteNonQuery();
connection.Close();
}
}
Hey guys I am using C# and I've successfully accessed my database and assigned variables etc but I want to access it a second time and for some reason it's failing at this point:
OleDbDataReader reader = command.ExecuteReader();
Here is the code snippets that might help you guys understand better. If anyone can point out what I might be doing wrong I'd be deeply grateful.
//#########################
// DATABASE OPERATIONS
//#########################
// Create the database connections
string usersConnString = (#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\kronix\Documents\theitguy.accdb");
OleDbConnection theitguyDBConn = new OleDbConnection(usersConnString);
//==============================
// Populate Customers Table
//==============================
try
{
// Open theitguy database connection
theitguyDBConn.Open();
// Select the fields you want to retrieve from in the database
string selectString = "SELECT ID, Name, Surname, Address, Town, County, Postcode, HomeNumber, MobileNumber, Email FROM Customers";
OleDbCommand command = new OleDbCommand(selectString, theitguyDBConn);
//Send the CommandText to the connection, and then build an OleDbDataReader.
//Note: The OleDbDataReader is forward-only.
OleDbDataReader reader = command.ExecuteReader();
// PROCESS THE DATABASE AND ADD THEM TO THE LISTS FOR USE LATER IN THE PROGRAM
while (reader.Read())
{
custID.Add(reader["ID"].ToString());
custName.Add(reader["Name"].ToString());
custSurname.Add(reader["Surname"].ToString());
custAddress.Add(reader["Address"].ToString());
custTown.Add(reader["Town"].ToString());
custCounty.Add(reader["County"].ToString());
custPostcode.Add(reader["Postcode"].ToString());
custHomeNumber.Add(reader["HomeNumber"].ToString());
custMobileNumber.Add(reader["MobileNumber"].ToString());
custEmail.Add(reader["Email"].ToString());
}
// Dispose of the data once used
reader.Dispose();
reader.Close();
// Close the database connection
theitguyDBConn.Close();
}
catch (Exception ex)
{
Console.Write("ERROR 201 (Form2): Error reading Customers table in theitguy Database\n");
}
//==============================
// Populate Repairs Table
//==============================
try
{
// Open theitguy database connection
theitguyDBConn.Open();
// Select the fields you want to retrieve from in the database
string selectString = "SELECT ID, CustID, Name, Surname, DateIn, Device, Colour, ContactNumber1, ContactNumber2, EstimatedCost, ReportedProblem, Diagnostics, EngineerRemarks, WorkCompleted, PartsUsed, PartsCost, PartsID, Engineer, TotalCost, DateCompleted FROM Repairs";
OleDbCommand command = new OleDbCommand(selectString, theitguyDBConn);
//Send the CommandText to the connection, and then build an OleDbDataReader.
//Note: The OleDbDataReader is forward-only.
OleDbDataReader reader = command.ExecuteReader(); //###IT'S FAILING HERE!!!###
// PROCESS THE DATABASE AND ADD THEM TO THE LISTS FOR USE LATER IN THE PROGRAM
while (reader.Read())
{
repID.Add(reader["ID"].ToString());
repCustID.Add(reader["ID"].ToString());
repName.Add(reader["ID"].ToString());
repSurname.Add(reader["ID"].ToString());
repDateIn.Add(reader["ID"].ToString());
repDevice.Add(reader["ID"].ToString());
repColour.Add(reader["ID"].ToString());
repContactNumber1.Add(reader["ID"].ToString());
repContactNumber2.Add(reader["ID"].ToString());
repEstimatedCost.Add(reader["ID"].ToString());
repReportedProblem.Add(reader["ID"].ToString());
repDiagnostics.Add(reader["ID"].ToString());
repEngineerRemarks.Add(reader["ID"].ToString());
repWorkCompleted.Add(reader["ID"].ToString());
repPartsUsed.Add(reader["ID"].ToString());
repPartsCost.Add(reader["ID"].ToString());
repPartsID.Add(reader["ID"].ToString());
repEngineer.Add(reader["ID"].ToString());
repTotalCost.Add(reader["ID"].ToString());
repDateCompleted.Add(reader["ID"].ToString());
}
// Dispose of the data once used
reader.Dispose();
reader.Close();
// Close the database connection
theitguyDBConn.Close();
}
catch (Exception ex)
{
Console.Write("ERROR 202 (Form2): Error reading Repairs table in theitguy Database\n");
}
Whoopsie, I made a boo boo .... I found out my problem.
I forgot to name the following properly:
repCustID.Add(reader["ID"].ToString());
repName.Add(reader["ID"].ToString());
repSurname.Add(reader["ID"].ToString());
Should be
repCustID.Add(reader["CustID"].ToString());
repName.Add(reader["Name"].ToString());
repSurname.Add(reader["Surname"].ToString());
Silly me.
Actually that wasn't the only fault...... the REAL PROBLEM was that I was trying to convert currency type in access into a string.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
My need is to write a code, which
creates a db
creates four tables
creates primary keys
creates foreign keys
and constraints like type int or boolean or string etc
Yes I know w3c shools has the sql codes, but the problem is I first need to detect if these things exists or not one by one.
And this is for me a great problem.
I tried to work with sql exceptions, but it does not provide way to categorize the exceptions --like databasethereexception--tablealreadythereEXCEPTION..
So please provide some coded examples or links for the above purpose,
note: yes I can google, but it is full full full of examples and codes, it gets too confusing, so hoping for straight professional examples please
Also a sample of the type of code i am working with
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.SqlClient;
using System.Data;
public partial class Making_DB : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//check or make the db
MakeDB();
CheckDB();
}
public void CheckDB()
{
try
{
string Data_source = #"Data Source=A-63A9D4D7E7834\SECOND;";
string Initial_Catalog = #"Initial Catalog=master;";
string User = #"User ID=sa;";
string Password = #"Password=two";
string full_con = Data_source + Initial_Catalog + User + Password;
SqlConnection connection = new SqlConnection(full_con);
connection.Open();
SqlDataAdapter DBcreatingAdaptor = new SqlDataAdapter();
DataSet ds2 = new DataSet();
SqlCommand CheckDB = new SqlCommand("select * from sys.databases where name = 'my_db'", connection);
DBcreatingAdaptor.SelectCommand = CheckDB;
DBcreatingAdaptor.Fill(ds2);
GridView1.DataSource = ds2;
GridView1.DataBind(); // do not forget this//
Response.Write("<br />WORKING(shows zero if db not there) checking by gridview rows: " + GridView1.Rows.Count.ToString());
Response.Write("<br />NOT WORKING(keeps on showing one always!) checking by dataset tables: " + ds2.Tables.Count.ToString());
DBcreatingAdaptor.Dispose();
connection.Close();
//Inaccesible due to protection level. Why??
//SqlDataReader reader = new SqlDataReader(CheckDB, CommandBehavior.Default);
}//try
catch (Exception e)
{
Response.Write(" checking:: " + e.Message);
}//catch
}//check db
public void MakeDB()
{
try
{
string Data_source = #"Data Source=A-63A9D4D7E7834\SECOND;";
//string Initial_Catalog = #"Initial Catalog=replicate;";
string User = #"User ID=sa;";
string Password = #"Password=two";
string full_con = Data_source + User + Password;
SqlConnection connection = new SqlConnection(full_con);
connection.Open();
//SqlCommand numberofrecords = new SqlCommand("SELECT COUNT(*) FROM dbo.Table_1", connection);
SqlCommand CreateDB = new SqlCommand("CREATE DATABASE my_db", connection);
//DataSet ds2 = new DataSet();
SqlDataAdapter DBcreatingAdaptor = new SqlDataAdapter();
DBcreatingAdaptor.SelectCommand = CreateDB;
DBcreatingAdaptor.SelectCommand.ExecuteNonQuery();
//check for existance
//select * from sys.databases where name = 'my_db'
DataSet ds2 = new DataSet();
SqlCommand CheckDB = new SqlCommand(" select * from sys.databases where name = 'my_db'", connection);
DBcreatingAdaptor.SelectCommand = CheckDB;
//DBcreatingAdaptor.SelectCommand.ExecuteReader();
DBcreatingAdaptor.Fill(ds2);
GridView1.DataSource = ds2;
//if not make it
}//try
catch (Exception e)
{
Response.Write("<br /> createing db error: " + e.Message);
}//catch
}//make db
}
As I've already mentioned in my comment - I would NEVER write out directly to the Response stream from a function like this! Pass back a string with an error message or something - but do NOT write out to the stream or screen directly.
You should use the best practice of wrapping SqlConnection and SqlCommand into using(...){.....} blocks to make sure they get properly disposed. Also, populating a gridview from within this code is really bad - you're mixing database access (backend) code and UI frontend code - really really bad choice. Why can't you just pass back the data table and then bind it in the UI front end code to the grid??
public DataTable CheckDB()
{
DataTable result = new DataTable();
try
{
string connectionString =
string.Format("server={0};database={1};user id={2};pwd={3}"
"A-63A9D4D7E7834\SECOND", "master", "sa", "two");
string checkQuery = "SELECT * FROM sys.databases WHERE name = 'my_db'";
using(SqlConnection _con = new SqlConnection(connectionString))
using(SqlCommand _cmd = new SqlCommand(checkQuery, _con))
{
SqlDataAdapter DBcreatingAdaptor = new SqlDataAdapter(_cmd);
DBcreatingAdaptor.Fill(_result);
}
}//try
catch (SqlException e)
{
// you can inspect the SqlException.Errors collection and
// get **VERY** detailed description of what went wrong,
// including explicit SQL Server error codes which are
// unique to each error
}//catch
return result;
}//check db
Also - you're doing the MakeDB() method way too complicated - why a table adapter?? All you need is a SqlCommand to execute your SQL command - you already have a method that checks that a database exists.
public void MakeDB()
{
try
{
string connectionString =
string.Format("server={0};database={1};user id={2};pwd={3}"
"A-63A9D4D7E7834\SECOND", "master", "sa", "two");
string createDBQuery = "CREATE DATABASE my_db";
using(SqlConnection _con = new SqlConnection(connectionString))
using(SqlCommand _cmd = new SqlCommand(createDBQuery, _con))
{
_con.Open();
_cmd.ExecuteNonQuery();
_con.Close();
}
}//try
catch (SqlException e)
{
// check the detailed errors
// error.Number = 1801 : "database already exists" (choose another name)
// error.Number = 102: invalid syntax (probably invalid db name)
foreach (SqlError error in e.Errors)
{
string msg = string.Format("{0}/{1}: {2}", error.Number, error.Class, error.Message);
}
}//catch
}//make db
I am very sure of the cross-over between this and the other question - however, it sounds to me like you are approaching this from the wrong end.
I would write this as a TSQL script, making use of EXEC to avoid problems with the checker, for example:
USE [master]
if not exists ( ... database ...)
begin
print 'creating database...'
exec ('...create database...')
end
GO
USE [database]
if not exists( ... check schema tables for 1st thing ... )
begin
print 'Creating 1st thing...'
exec ('...create 1st thing...')
end
if not exists( ... check schema tables for 2nd thing ... )
begin
print 'Creating 2nd thing...'
exec ('...create 2nd thing...')
end
if not exists( ... check schema tables for 3rd thing ... )
begin
print 'Creating 3rd thing...'
exec ('...create 3rd thing...')
end
Then you can gradually extend this script as your schema changes, and all you need to do is re-run the script for it to update the database.
May be it is not directly you want, but for easy database creation & population from .Net review usage of wide migrate tool. My preference (Migrator.NET) but full review can be found there: http://flux88.com/blog/net-database-migration-tool-roundup/