I am writing a small XAML/C#/MySQL database and wanted to create a query that accepts parameters. However, the test query that I am setting up fails when I try to create it
var con = new MySqlConnection(ClsVariables.StrDb);
con.Open();
var command = new MySqlCommand("", con);
command =
new MySqlCommand("Create View r2_Add_Edit_View as SELECT era.contact_id, era.n_family FROM era WHERE era.contact_id = #ContactID", con) command.ExecuteNonQuery();
con.Close();
When I change the #ContactID to a specific number - it works fine.
After that I will need to create a recordset, and pass the parameter to it (but I can ask that in a secondary question).
Thanks as always.
When I change the #ContactID to a specific number - it works fine.
Well, you don't pass the parameter, so just add it to your command:
public class MySqlConnector
{
private readonly string _connString;
public MySqlConnector(string connString)
{
_connString = connString;
}
private MySqlCommand _command;
const string Sql = "Create View r2_Add_Edit_View as SELECT era.contact_id, era.n_family FROM era WHERE era.contact_id = #ContactID";
public void CreateView(int contactId)
{
if(_command == null)
{
_command = new MySqlCommand();
_command.CommandText = Sql;
_command.Connection = _connString;
}
_command.Parameters.AddWithValue("#ContactID", contactId);
_command.ExecuteNonQuery();
_command.Close();
}
}
Try to use Command AddParameters method.
command.Parameters.Add("#ContactID", SqlDbType.Int);
command.Parameters["#ContactID"].Value = value;
Related
I'm new at coding and I need help for a school project.
I want to update a database using MySQL but I can't find out how to get the update working.
I have googled a bit but I haven't been able to find a solution so I figured I'd ask the question on this site.
I have successfully made a connection to the database and show the contents in a data grid. The connection has a name: "conn". If anyone knows a way on how I can get the update to work I'd be happy to hear from you!
This is my XAML.CS code:
public void Click_btnBewerk(object sender, RoutedEventArgs e)
{
string vzitter2 = txtVZitter.Text;
string info2 = txtInfo.Text;
string zetels2 = txtZetels.Text;
string stroming2 = txtStroming.Text;
string partij = cmPartijen.Text;
conn.Updateinfo();
}
This is my DBconn code:
public DataView Updateinfo()
{
conn.Open();
MySqlCommand command = conn.CreateCommand();
command.CommandText = "UPDATE partijen SET fvzitter='vzitter2', info='info2', zetels='zetels2', stroming='stroming2' WHERE partij='partij'";
MySqlDataReader reader = command.ExecuteReader();
DataTable dtData = new DataTable();
dtData.Load(reader);
conn.Close();
return dtData.DefaultView;
}
you are doing a Reading action on the db instead an update.
Just replace your code with this
public void Updateinfo()
{
conn.Open();
MySqlCommand command = conn.CreateCommand();
command.CommandText = "UPDATE partijen SET fvzitter='vzitter2', info='info2', zetels='zetels2', stroming='stroming2' WHERE partij='partij'";
command.ExecuteNonQuery();
conn.Close();
}
if you want pass the variables to the updateinfo method just do it
private void Updateinfo(string fvzitter, string info, string zetels, string stroming, string partij)
{
string query = "UPDATE partijen SET fvzitter=#fvzitter, info=#info, zetels=#zetels, stroming=#stroming WHERE partij=#partij"
conn.Open();
MySqlCommand command = conn.CreateCommand();
command.CommandText = query;
command.Parameters.AddWithValue("#fvzitter", fvzitter);
command.Parameters.AddWithValue("#info", info);
command.Parameters.AddWithValue("#zetels", zetels);
command.Parameters.AddWithValue("#stroming", stroming);
command.Parameters.AddWithValue("#partij", partij);
command.ExecuteNonQuery();
conn.Close();
}
I'm trying to pass a string (the output of a function) to an SqLite query and have it update a database with it. I get an error telling me that string is not a valid data type.
IList<string> classList = new List<string>(){ "Saber", "Archer", "Lancer", "Rider",
"Caster", "Assassin", "Berserker", "Ruler", "Avenger", "Moon Cancer"};
public string setClass(int uid)
{
string newClass;
int remainder = uid % 10;
newClass = classList[remainder];
return(newClass);
}
[NadekoCommand, Usage, Description, Aliases]
public async Task initialiseClasses()
{
using (SqliteConnection _db = new SqliteConnection(#"Filename=.\myDb.db"))
{
_db.Open();
string newSQL = "ALTER TABLE DiscordUser ADD Class char";
SqliteCommand command = new SqliteCommand(newSQL, _db);
command.ExecuteReader();
string tempClass = setClass(7); //temporary input
newSQL = "UPDATE DiscordUser SET Class = #newClass";
command.Parameters.Add(new SqliteParameter("#newClass", SqliteType.Text).Value = tempClass);
command = new SqliteCommand(newSQL, _db);
command.ExecuteReader();
}
}
I'm trying to pass tempClass into the Sqlite query.
You were creating a new command after you assigned the parameter to the command which resulted in a command without parameters being executed.
The Add on the parameter collection can be rewritten so it is more fluent, see change below.
ExecuteReader should be ExecuteNonQuery
If you structure your code with using blocks it is easier to see the scope of the command instance. See below:
public async Task initialiseClasses()
{
using (SqliteConnection _db = new SqliteConnection(#"Filename=.\myDb.db"))
{
_db.Open();
string newSQL = "ALTER TABLE DiscordUser ADD Class char";
using(SqliteCommand command = new SqliteCommand(newSQL, _db))
{
command.ExecuteNonQuery();
}
string tempClass = setClass(7); //temporary input
newSQL = "UPDATE DiscordUser SET Class = #newClass";
using(SqliteCommand command = new SqliteCommand(newSQL, _db))
{
command.Parameters.Add("#newClass", SqliteType.Text).Value = tempClass;
command.ExecuteNonQuery();
}
}
}
I am trying to get the first result from my SQL table row. But I get the constraint by using the class to get the result.
I want to display supplier code by entering supplier email first like this.
Class Program
protected void Button_register_supplier_Click(object sender, EventArgs e)
{
string email_supplier = TextBox_email_supplier.Text;
c_supplier reg = new c_supplier();
reg.tampil_register(email_supplier);
Label_tampil_kode_user.Text = reg.tampil_register().ToString();
}
Class Supplier
public string tampil_register(string email_supplier)
{
SqlCommand command = new SqlCommand();
command.CommandText = "SELECT kode_supplier FROM tb_supplier WHERE email_supplier = #email_supplier";
command.Parameters.AddWithValue("#email_supplier", email_supplier);
command.CommandType = CommandType.Text;
command.Connection = con;
con.Open();
SqlDataReader dr = command.ExecuteReader();
string hasil;
while (dr.Read())
{
hasil = dr.GetValue(0).ToString();
return hasil;
}
}
So I will throw the value from my program class to supplier class to get the user code value. Then this user code will be displayed again in my program class by displaying it in my text label.
Your c_supplier class have a design flaw - you are using a class-level SQLConnection instance. This is a problem since it means you are not taking advantage of the built-in connection pool (and since it's implementing the IDisposable interface you are risking a memory leak). You should always use a local variable for SQLConnection, and dispose it as soon as possible. Also, you are using ExecuteReader when you need to use ExecuteScalar, and you are not disposing your SQLCommand instance as well.
A better code would be something like this:
public string tampil_register(string email_supplier)
{
using(var con = new SqlConnection(connectionString))
{
using(var command = new SqlCommand("SELECT kode_supplier FROM tb_supplier WHERE email_supplier = #email_supplier", con))
{
command.Parameters.Add("#email_supplier", SqlDbType.VarChar).Value = email_supplier;
con.Open();
var hasil = command.ExecuteScalar();
if(hasil != null && hasil != DBNull.Value)
{
return hasil.ToString();
}
}
}
return ""; // in case no record was found
}
That being said, you are also calling the tampil_register method twice - once with a string and once without - so your button click code should probably be:
protected void Button_register_supplier_Click(object sender, EventArgs e)
{
c_supplier reg = new c_supplier();
Label_tampil_kode_user.Text = reg.tampil_register(TextBox_email_supplier.Text);
}
In my project, I have a DBAdapter class that deals with database queries.
public class DBAdapter
{
private OleDbConnection _connection;
private void _Connect()
{
this._connection = new OleDbConnection();
_connection.ConnectionString = ConfigurationManager.AppSettings["Accessconnection"];
_connection.Open();
}
private void _Disconnect()
{
_connection.Close();
}
public DataTable Select(string query, OleDbParameterCollection parameters = null)
{
OleDbCommand cmd = new OleDbCommand();
OleDbDataAdapter dataAdapter = new OleDbDataAdapter();
DataSet dataSet = new DataSet();
DataTable dataTable = new DataTable();
query = "SELECT " + query;
if (parameters != null)
{
foreach (OleDbParameter parameter in parameters)
{
cmd.Parameters.Add(parameter);
}
}
this._Connect();
cmd.Connection = _connection;
cmd.CommandText = query;
if (parameters != null) {
cmd.Prepare();
}
dataAdapter.SelectCommand = cmd;
dataAdapter.Fill(dataSet, "results");
this._Disconnect();
dataTable = dataSet.Tables["results"];
return dataTable;
}
}
In order to perform prepared queries, the Select method has an optionnal OleDBParameterCollection parameter.
Then, I have multiple Mappers for each domain object in my project, for example UserMapper, that use DataAdapter class to run queries (for example find user by id).
public class UserMapper : DataMapperAbstract
{
public User findByID(int id)
{
User user = new User()
string query = "* FROM USER WHERE idUser = ?";
OleDbParameterCollection parameters = new OleDbParameterCollection();
parameters.Add(new OleDbParameter("idUser", OleDbType.Integer).Value = id);
// Prepared query
DataTable results = adapter.Select(query, parameters);
this._populateData(user, results.Rows[0]);
return user;
}
}
Unfortunately, I have an error at this line
OleDbParameterCollection parameters = new OleDbParameterCollection();
VS says that the type OleDbParameterCollection has no constructor defined, and I don't really understand what is the problem here. Maybe I don't have rights to instantiate OleDbParameterCollection, but in that case, how should I pass a collection of parameters to my DBAdapter's method ?
OleDbParameterCollection doesn't expose public constructor we can access. It doesn't meant to be used that way so, simply change your method parameter to accept list of OleDbParameter instead of OleDbParameterCollection :
public DataTable Select(string query, List<OleDbParameter> parameters = null)
{
}
Then use it accordingly :
List<OleDbParameter> parameters = new List<OleDbParameter>();
parameters.Add(new OleDbParameter("idUser", OleDbType.Integer){ Value = id });
// Prepared query
DataTable results = adapter.Select(query, parameters);
OleDbParameterCollection has no public constructors.
When the OleDbDataAdapter object is instantiated it automatically creates an OleDbParameterCollection object for you within the SelectCommand object.
Here is some code from MSDN that I found:
OleDbDataAdapter adapter =
new OleDbDataAdapter(queryString, connection);
// Set the parameters.
adapter.SelectCommand.Parameters.Add(
"#CategoryName", OleDbType.VarChar, 80).Value = "toasters";
Here is the link:
http://msdn.microsoft.com/en-us/library/system.data.oledb.oledbparametercollection(v=vs.110).aspx
You may need to modify the way you run the query a little bit. But, it looks like you've already got an adapter object in there, so it shouldn't be too hard.
I'm developing a C# solution with data access to Oracle.
And would like to have a generic solution about query.
Here is a part of my code :
public DataTable GetData(string query)
{
DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OracleClient");
using (DbConnection conn = factory.CreateConnection())
{
try
{
DbConnectionStringBuilder csb = factory.CreateConnectionStringBuilder();
csb["Data Source"] = #"Northwind";
csb["User Id"] = #"Northwind";
csb["Password"] = #"Northwind";
conn.ConnectionString = csb.ConnectionString;
conn.Open();
using (DbCommand cmd = conn.CreateCommand())
{
cmd.CommandText = query;
using (DataTable dt = new DataTable())
{
DbDataAdapter da = factory.CreateDataAdapter();
cmd.CommandType = CommandType.Text;
da.SelectCommand = cmd;
da.Fill(dt);
return dt;
}
}
}
catch (Exception ex)
{
throw new Exception("Error", ex);
}
finally
{
if (conn.State != ConnectionState.Closed)
conn.Close();
}
}
}
And I call my method like this :
DataAccess.Provider data = new DataAccess.Provider();
DataTabel dt = dt.GetData("select * from myTable);
This works pretty good but this is not my aim.
I have a second class called CL_mpg with all my SQL queries.
class CL_MPG
{
public string rq_sql;
public string selectParam(string param)
{
this.rq_sql = "select * from myTable where id = '" + param + "';";
return this.rq_sql;
}
public string select()
{
this.rq_sql = "select * from myTable";
return this.rq_sql;
}
//...
}
And I would like to use my methods selectParam and/or select to fill my datatable, but I don't know how to do that.
Although others complain at your learning attempt, everyone has to start somewhere. Your method is actually an ok start, but I would change the parameter from a string to a DbCommand object. Then, you can create your methods to properly build the command and set proper parameters. Then pass the entire prepared command to your wrapper method (that creates connection, tests open successful, queries data, etc) and have your method return a DataTable object as you have... something like
public class CL_MPG
{
private DataTable GetData(DbCommand cmd )
{
// do all the same as you have with exception of your USING DBCOMMAND.
// just set the connection property of the incoming command to that of
// your connection created
// AT THIS PART --
// using (DbCommand cmd = conn.CreateCommand())
// {
// cmd.CommandText = query;
// just change to below and remove the closing curly bracket for using dbcommand
cmd.Connection = conn;
}
// Now, your generic methods that you want to expose for querying
// something like
public DataTable GetAllData()
{
DbCommand cmd = new DbCommand( "select * from YourTable" );
return GetData( cmd );
}
public DataTable GetUser( int someIDParameter )
{
DbCommand cmd = new DbCommand( "select * from YourTable where ID = #parmID" );
cmd.Parameters.Add( "#parmID", someIDParameter );
return GetData( cmd );
}
public DataTable FindByLastName( string someIDParameter )
{
DbCommand cmd = new DbCommand( "select * from YourTable where LastName like #parmTest" );
cmd.Parameters.Add( "#parmTest", someIDParameter );
return GetData( cmd );
}
}
Notice the command is being built and fully prepared and parameterized vs concatination of strings as prior comment was made which could expose you to SQL-injection. As for the parameters, and not querying Oracle, they may need to be tweaked some. Different engines use slightly different conventions. If connecting to SQL-Server database, it uses "#" to identify a parameter. In SyBase Advantage Database, it uses ":". Using Visual FoxPro, a simple "?" placeholder is used.
Also, if your query has many criteria, just keep adding additional "#parm" type placeholders, then add your parameters in the same order as they appear in your query just to make sure you didn't miss any. Some functions could have none, one or more based on your needs. Then, in the samples provided, its as simple as doing something like
DataTable whoIs = yourCL_MPGObject.GetUser( 23 );
if( whoIs.Rows.Count > 0 )
MessageBox.Show( whoIs.Rows[0]["WhateverColumnName"] );