I have an application that allows my user to run queries against a database of their choice. The database can be either SQL server or Oracle. this method accepts two parameters from another class, first parameter is the connection string to the database the user chooses, and the second is the database type. that part works fine. what I am trying to do is cut back on the code I need to write and not type the query and connection stuff over and over. so, I would like to do something like this. Obviously this wont work, but I'm open to most solutions.
public void createTable(string connectstring, string rdbms)
{
if (rdbms == "oracle")
{
con = new OracleConnection(connectionString);
con.Open();
OracleCommand query = con.CreateCommand();
}
else if (rdbms == "SQL Server")
{
con = new SqlConnection(connectionString);
con.Open();
SqlCommand query = con.CreateCommand();
}
else
{
// broke
}
query.CommandText = "CREATE TABLE " + RndName +
" (Col0 Varchar(10),Col1 Varchar(10), Col2 Varchar(10))";
query.ExecuteNonQuery();
con.Close();
executeInsertTransactions(connectstring);
}
This problem is generally solved via interfaces. There may be these common interfaces:
IConnection
IDataProvider
IRepository
Implement interfaces using MySql database, such as class MySqlConnection : IConnection. For Oracle, add class MsOracleConnection : IConnection.
Ideally you should abstract all the functionality into common interfaces. You will have to provide implementations for each database/storage engine you want to support. At runtime, you will use IoC container and DI principle to set up the current implementation. All the child dependencies will use interfaces passed in as parameters to constructor (or properties or methods)
You can create more abstract code by leveraging the framework's DbProviderFactory and using the obtained Db* classes.
Dim con As System.Data.IDbConnection
Dim cmd As System.Data.IDbCommand
Select Case ConDBType
Case TypeDatabase.SqlServer
con = New OleDbConnection(CN.ConnectionString)
cmd = New OleDbCommand
Case TypeDatabase.MySql
con = New MySqlConnection(CNMySql.ConnectionString)
cmd = New MySqlCommand
Case TypeDatabase.Access
Call InitNameing()
ConDBAccess.DataSource = PreparToRootNameing() & "\T" & NAME_SYSTEMDB
con = New OleDbConnection(CN.ConnectionString)
cmd = New OleDbCommand
End Select
cmd.Connection = con
con.Open()
cmd.CommandText = SQLUpdate
cmd.ExecuteNonQuery()
Related
Can somebody tell me the pros and cons of this code? I know I can use stored procedures instead, but would it be easy to SQL inject this code considering I had a textbox where admins could input the commentid?
string commentId = a.Text;
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ForumDatabaseConnectionString"].ConnectionString);
con.Open();
string sql = "DELETE FROM Comment WHERE Comment.commentId = #commentid";
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.AddWithValue("#commentid", commentId);
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
Yes, it looks fine, since you're using paramterized sql. However, you haven't given your table an alias, so I thing your sql should be
DELETE FROM Comment WHERE commentId = #commentid
As well as protecting you from sql injection attacks, Sql Server will know that this sql may be called again with different parameters, so can cache an efficient execution plan for it.
As an aside, you should always dispose of connections after using them.
string commentId = a.Text;
using (SqlConnection con = new SqlConnection(ConfigurationManager
.ConnectionStrings["ForumDatabaseConnectionString"].ConnectionString))
{
con.Open();
string sql = "DELETE FROM Comment WHERE Comment.commentId = #commentid";
using(SqlCommand cmd = new SqlCommand(sql, con))
{
cmd.Parameters.AddWithValue("#commentid", commentId);
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
As you can see, there is a fair amount of code for such a simple operation. You may wish to take a look at dapper, which will remove a lot of these issues. There are many libraries to help you, which are off-topic here, but its a lightweight, popular one
Pros:
Good thing is you are using parameters for command which is sql injection safe.
Cons:
Not well written.
Not using function for CRUD. Always Use functions to do CRUD operation.
No Use of Using block. Always use using block, so you don't need to dispose connection & command. You don't need to manually close it.
Use following code in DataAccessLayer.
public void DeleteComment(int commentId)
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ForumDatabaseConnectionString"].ConnectionString))
{
con.Open();
string sql = "DELETE FROM Comment WHERE Comment.commentId = #commentid";
using (SqlCommand cmd = new SqlCommand(sql, con))
{
cmd.Parameters.AddWithValue("#commentid", commentId);
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
}
You can write connection open code in separate function too.
Check this article for more detail:
https://www.codeproject.com/Articles/813965/Preventing-SQL-Injection-Attack-ASP-NET-Part-I
I am building an application for a group of friends and myself to use for DnD sessions. Part of the program involves taking all of the values that are entered for our characters, items, etc and storing them to a database. I have the database built, and am pulling from the database into the program, however I am unable to return data to the database. I have the data coming into a dataset, and all of my edits are affecting the dataset, but I cannot get anything to affect the actual source database tables.
Below I have the button that I intend to use to update items in the characters' packs. I have both dataadapter, and tableadapter methods included that I have tried.
private void btnaddpack_Click(object sender, EventArgs e)
{
if (txtbxpack.Text != "")
{
/*connection.Open();
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "UPDATE Pack SET Item = (#ItemName)" + "WHERE Id = '" + this.lstpack.SelectedValue + "';";
cmd.ExecuteNonQuery();
cmd.Clone();*/
string packitem = txtbxpack.Text; //will take item from an textbox
this.packTableAdapter.Insert(packitem);
this.Validate();
this.packBindingSource.EndEdit();
this.packTableAdapter.Update(this.dnD_MachineDataSet.Pack);
}
PopulatePack();
Here is my populate code in case someone needs that:
private void PopulatePack()
{
using (connection = new SqlConnection(connectionString)) //this is all about opening the connection to the sqldatabase, normally it would need to be closed, but this uses idisposable, so it will close itself
using (SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Pack", connection))
{
DataTable packtable = new DataTable();
adapter.Fill(packtable);
lstpack.DataSource = packtable;
lstpack.DisplayMember = "Item";
lstpack.ValueMember = "Id";
}
}
As mentioned above, all of the changes are appearing whenever I re-populate the listboxes that draw upon the dataset, hence why this is an issue of trying to get that data back into the source database. I will make the obligatory "I'm relatively new to using databases" statement as it will do no good to pretend that I am an expert.
Thanks.
In the commented code, you would need to do the following:
assign the connection object to the SqlCommand object's Connection
property
pass the item name to your #ItemName parameter
assign a parameter value to the 'Id' column in the WHERE clause
remove, 'cmd.Clone();', and replace with, 'connection.Close();'
Here is what the code should look like:
connection.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = connection;
cmd.CommandText = "UPDATE Pack SET Item = (#ItemName) WHERE Id = #ID;";
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#ItemName", txtbxpack.Text);
cmd.Parameters.AddWithValue("#ID", this.lstpack.SelectedValue);
cmd.ExecuteNonQuery();
connection.Close();
I had a method in which I intend for it to delete all data from the table. However, even as it is called, the deletion didn't happen at all.
Here below is the method.
Let's assume that the data is already loaded in the table.
Table "CartListClone" has 5 columns (excluding the ID). The table as you can see in the connection string derives from Access.
public void deleteEverything() {
OleDbConnection connect =
new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;
Data Source=POSDB.accdb;
Persist Security Info = False");
connect.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = connect;
command.CommandText = "DELETE * FROM CartListClone";
}
As of now, I feel that the problem is rooted at the method.
Is there something that I did wrong here?
Much appreciated for any help.
UPDATE: Following sstan's suggestion, here below is the rewritten method.
public void deleteEverything() {
OleDbConnection connect =
new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;
Data Source=POSDB.accdb;
Persist Security Info = False");
connect.Open();
OleDbCommand command = new OleDbCommand("DELETE * FROM CartListClone");
command.Connection = connect;
command.ExecuteNonQuery();
}
You're never executing the command object. You're missing this line at the end:
command.ExecuteNonQuery();
I'm quite used to using c# with SQL server. I have no idea why a simple statement would fail to insert data. My code is as follows:
query = "INSERT INTO MCDPhoneNumber ([MCDID],[PhoneNumber])" +
"VALUES("+maxid+", '"+tel+"')";
SqlConnection conn = new SqlConnection("Data Source=source; ...");
SqlCommand newCommand = new SqlCommand(query, conn);
int success= myCommand.ExecuteNonQuery();
if (success!= 1)
{
MessageBox.Show("It didn't insert anything:" + query);
}
First of all let me tell that I know that I should use parameters for data and I initially did, but when it failed I tried a simple query and it still fails. For addition I can tell that I have a similar insert just before that one in another table and it works. What's funnier is that when I copy paste query to SQL Server Management Studio it works. It also doesn't report any error in process.
====================== Edit ===============================
If you wish to use old command object (i.e. myCommand) then use following code instead of creating a new command(newCommand)
myCommand.CommandText = query;
myCommand.CommandType = System.Data.CommandType.Text;
And then execute it
you are binding query with newCommand and executing myCommand.
====================== Edit ===============================
SqlCommand newCommand = new SqlCommand(query, conn);
here you have defined newCommand for SQLCOMMAND object
int success= myCommand.ExecuteNonQuery();
and you are accessing it as myCommand
And moreover i think you are not opening connection
First of all, you define your command as newCommand but you executing your myCommand.
You should always use parameterized queries for your sql queries. This kind of string concatenations are open for SQL Injection attacks.
query = "INSERT INTO MCDPhoneNumber (MCDID, PhoneNumber) VALUES(#maxid, #tel)";
using(SqlConnection conn = new SqlConnection("Data Source=source; Initial Catalog=base; Integrated Security = true"))
{
SqlCommand newCommand = new SqlCommand(query, conn);
conn.Open();
newCommand.Parameters.AddWithValue("#maxid", maxid);
newCommand.Parameters.AddWithValue("#tel", tel);
int success= newCommand.ExecuteNonQuery();
if (success != 1)
{
MessageBox.Show("It didn't insert shit:" + query);
}
}
And please be more polite about your error messages :)
Does anyone know how can I central the db connection in c# .net (perhaps in the mian.master)?
I have the following code for the db connection and used to call to the difference stored proc to retrieved data.
string strConnString = ConfigurationManager.ConnectionStrings["testString"].ConnectionString;
SqlConnection mySqlConnection = new SqlConnection(strConnString);
SqlCommand mySqlCommand = mySqlConnection.CreateCommand();
mySqlCommand.CommandText = "EXEC app_campaign_select #CampaignID=" + Request.QueryString["ixCampaign"].ToString();
mySqlConnection.Open();
SqlDataReader mySqlDataReader = mySqlCommand.ExecuteReader();
Instead of coding it in every pages and connection to the db multiple times, any way I can code the following connection code in the master page and only connecting to the db once, then each page can call it when need to be connect into the db
string strConnString = ConfigurationManager.ConnectionStrings["testString"].ConnectionString;
SqlConnection mySqlConnection = new SqlConnection(strConnString);
SqlCommand mySqlCommand = mySqlConnection.CreateCommand();
SqlDataReader mySqlDataReader;
Add it to a static DAL class and add parameters as needed.
public static void YourFunction() {
// your code
}
Note:
Beware this line: mySqlCommand.CommandText = "EXEC app_campaign_select #CampaignID=" + Request.QueryString["ixCampaign"].ToString();
If that QueryString comes from a user entered value somewhere, you could be open to SQL Injection.
Sure. Just create a helper class that has a few static methods in them for each type of return type you could have. Pass to one a string for stored procedure name and have an overloaded one that takes a string for a sql statment that you would pass in. You can also have one that just returns back a scalar value as well. So you would probably have 3 or so static methods you could call from any page.