C# - Increase method reusability - c#

private static void ReadOrderData(string connectionString)
{
string queryString =
"SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlCommand command =
new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// Call Read before accessing data.
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
// Call Close when done reading.
reader.Close();
}
}
How can I enhance the method above to accept any queryString? The problem is in the while. There's a fixed # of columns I can read. I want to be able to read any number of columns so that I can populate and return a DataSet. How can I do it?

You can do something along these lines:
private static void ReadOrderData(string connectionString,
string query, Action<SqlDataReader> action)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand command =
new SqlCommand(query, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// Call Read before accessing data.
while (reader.Read())
{
action(reader);
}
// Call Close when done reading.
reader.Close();
}
}

You're really barking up the wrong tree. You shouldn't be using "methods that accept query strings". You should raise the level of abstraction by using Entity Framework or the like.
You will then not need to use the above code because it will not exist. Those who would have called that code will do something like this:
var orders = from o in ordersDAL.Orders
select new {o.OrderID, o.CustomerID};
foreach (var order in orders)
{
Console.WriteLine("{0}, {1}", order.OrderID, order.CustomerID);
}
Your code is badly designed in any case. Why in the world would you combine the fetching of the data with the use of it? That while loop should not be in that same method.
I would use something like the answer from obrok, but I would add the ability to use parameters.
Also, the SqlCommand and SqlDataReader both need to be within a using block:
private static void ReadOrderData(string connectionString,
string query, Action<SqlDataReader> action)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command =
new SqlCommand(query, connection)) {
connection.Open();
using (SqlDataReader reader = command.ExecuteReader()) {
// Call Read before accessing data.
while (reader.Read())
{
action(reader);
}
// No need to call Close when done reading.
// reader.Close();
} // End SqlDataReader
} // End SqlCommand
}
}

Use SqlDataAdapter:
private static DataSet ReadData(string connectionString, string queryString)
{
DataSet dataSet;
using (SqlConnection connection =
new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command =
new SqlCommand(queryString, connection);
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(dataSet);
}
return dataSet;
}
Or something like this.

How I'm doing this:
(basically idea is to use DataSet along with IDataAdapter)
DataSet ds = null;
List<SqlParameter> spParams = ...
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
using (SqlCommand command = new SqlCommand(spName, connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Clear();
command.Parameters.AddRange(spParams);
connection.Open();
IDbDataAdapter da = new SqlDataAdapter();
da.SelectCommand = command;
ds = new DataSet("rawData");
da.Fill(ds);
ds.Tables[0].TableName = "row";
foreach (DataColumn c in ds.Tables[0].Columns)
{
c.ColumnMapping = MappingType.Attribute;
}
}
}
// here is you have DataSet flled in by data so could delegate processing up to the particular DAL client

You said you tried EF, but did you try Dapper ? looks like a simple enough ORM that should work with your database (it's raw SQL), and will avoid you most of this mapping code. Dapper is used in StackOverflow so it cannot be too bad :)

Same suggestion as 'WorkerThread' but change the Method Signature to:
private static DataSet ReadOrderData(string connectionString, string queryString)
{
// do work
}
Drop the following line from 'WorkerThread' example:
string queryString = "SELECT OrderID, CustomerID FROM dbo.Orders;";
Once you have made these two changes to 'WorkerThread's' method it should be perfect for what you need.

Look at the DataTable.Load method. Or, for a finer level of control, check out the properties and methods on IDataReader, such as FieldCount, GetFieldType, and GetName.

Related

How can I get SQL result into a STRING variable?

I'm trying to get the SQL result in a C# string variable or string array. Is it possible? Do I need to use SqlDataReader in some way?
I'm very new to C# functions and all, used to work in PHP, so please give a working example if you can (If relevant I can already connect and access the database, insert and select.. I just don't know how to store the result in a string variable).
This isn't the single greatest example in history, as if you don't return any rows from the database you'll end up with an exception, but if you want to use a stored procedure from the database, rather than running a SELECT statement straight from your code, then this will allow you to return a string:
public string StringFromDatabase()
{
SqlConnection connection = null;
try
{
var dataSet = new DataSet();
connection = new SqlConnection("Your Connection String Goes Here");
connection.Open();
var command = new SqlCommand("Your Stored Procedure Name Goes Here", connection)
{
CommandType = CommandType.StoredProcedure
};
var dataAdapter = new SqlDataAdapter { SelectCommand = command };
dataAdapter.Fill(dataSet);
return dataSet.Tables[0].Rows[0]["Item"].ToString();
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
finally
{
if (connection != null)
{
connection.Close();
}
}
}
It can definitely be improved, but it would give you a starting point to work from if you want to go down a stored procedure route.
Try This:
SqlConnection con=new SqlConnection("/*connection string*/");
SqlCommand SelectCommand = new SqlCommand("SELECT email FROM table1", con);
SqlDataReader myreader;
con.Open();
myreader = SelectCommand.ExecuteReader();
List<String> lstEmails=new List<String>();
while (myreader.Read())
{
lstEmails.Add(myreader[0].ToString());
//strValue=myreader["email"].ToString();
//strValue=myreader.GetString(0);
}
con.Close();
accessing the Emails from list
lstEmails[0]->first email
lstEmails[1]->second email
...etc.,
You could use an SQL Data Reader:
string sql = "SELECT email FROM Table WHERE Field = #Parameter";
string variable;
using (var connection = new SqlConnection("Your Connection String"))
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("#Parameter", someValue);
connection.Open();
using (var reader = command.ExecuteReader())
{
//Check the reader has data:
if (reader.Read())
{
variable = reader.GetString(reader.GetOrdinal("Column"));
}
// If you need to use all rows returned use a loop:
while (reader.Read())
{
// Do something
}
}
}
Or you could use SqlCommand.ExecuteScalar()
string sql = "SELECT email FROM Table WHERE Field = #Parameter";
string variable;
using (var connection = new SqlConnection("Your Connection String"))
using (var command = new SqlCommand(sql, connection))
{
command.Parameters.AddWithValue("#Parameter", someValue);
connection.Open();
variable = (string)command.ExecuteScalar();
}
This May help you For MySQL
MySqlDataReader reader = mycommand.ExecuteReader();
while (reader.Read())
{
TextBox2.Text = reader.ToString();
}
For SQL
using (SqlCommand command = new SqlCommand("*SELECT QUERY HERE*", connection))
{
//
// Invoke ExecuteReader method.
//
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
TextBox2.Text = reader.GetString(0);
}
}
Try this:
public string SaveStringSQL(string pQuery, string ConnectionString)
{
var connection = new Conexao(ConnectionString);
connection.Open();
SqlCommand command = new SqlCommand(pQuery, connection.Connection);
var SavedString = (string)command.ExecuteScalar();
connection.Close();
return SavedString;
}
The ExecuteScalar function saves whatever type of data there is on your database - you just have to specify it.
Keep in mind that it can only save one line at a time.

Returning result of SqlCommand in class

As I'm not programming long time I would like to ask you if there is way to call result of this SqlCommand which is in class called klientClass
I was thinking that it could look something like this:
private static void ReadFirma()
{
string queryString =
"SELECT rocnik from FIRMA;";
using (SqlConnection connection = new SqlConnection(myConnection.DataSource.ConnectionString
))
{
SqlCommand command = new SqlCommand(
queryString, connection);
connection.Open();
int result= Convert.ToInt32(command.ExecuteScalar());
try
{
}
finally
{
reader.Close();
}
}
}
Because I need to insert this result into my report parameter here:
this.klientTableAdapter.Fill(this.prehled_zajezdu.HereReturnResult);
this.reportViewer1.RefreshReport();
I'm sorry for quiet low-quality question, hope not to receive down-votes.
This is how you can retrieve and use the value from the database in your Fill method (provided that the Fill method takes an argument of the type int and that the myConnection field is available from the static method)
private static int ReadFirma()
{
string queryString = "SELECT rocnik from FIRMA";
using (var connection =
new SqlConnection(myConnection.DataSource.ConnectionString))
using(var command = new SqlCommand(queryString, connection))
{
connection.Open();
return Convert.ToInt32(command.ExecuteScalar());
}
}
void SomeMethod()
{
this.klientTableAdapter.Fill(ReadFirma());
}
You can use DataTable object for your Goal.
private static DataTable ReadFirma()
{
string queryString = "SELECT rocnik from FIRMA";
using (var connection =
new SqlConnection(myConnection.DataSource.ConnectionString))
using(var command = new SqlCommand(queryString, connection))
{
connection.Open();
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter();
da.SelectCommand = command;
da.Fill(dt);
return dt;
}
}
void SomeMethod()
{
this.klientTableAdapter.Fill(ReadFirma());
}

SqlDataAdapter with using keyword

Is this the following code healthy? Or I don't need to use the using keyword as the SqlDataAdapter will handle closing the connection?
public static DataSet Fetch(string sp, SqlParameter [] prm)
{
using (SqlConnection con = new SqlConnection(ConStr))
{
using (SqlCommand cmd = con.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = sp;
cmd.Parameters.AddRange(prm);
using (SqlDataAdapter dta = new SqlDataAdapter(cmd))
{
DataSet dst = new DataSet();
dta.Fill(dst);
return dst;
}
}
}
}
#MarkGravell I need a suggestions here, I am really looking to use DataReader, but I was looking all the time to use the using keyword to ensure closing the connections. Where with DataReader we can not use it because it will close the connection if we want to return the DataReader back to some method.
So do you think the following technique is fine with DataReader and the using keyword:
public static SqlDataReader Fetch(string sp, SqlParameter [] prm)
{
SqlCommand cmd = new SqlConnection(ConStr).CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = sp;
cmd.Parameters.AddRange(prm);
cmd.Connection.Open();
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
using (SqlDataReader dtrPrize = Sql.Fetch("SelectPrize", new SqlParameter[] { new SqlParameter("id", id) }))
{
dtrPrize.Read();
Prize prize = new Prize();
prize.id = (int)dtrPrize[dtrPrize.GetOrdinal("id")];
prize.artitle = (string)dtrPrize[dtrPrize.GetOrdinal("artitle")];
prize.entitle = (string)dtrPrize[dtrPrize.GetOrdinal("entitle")];
prize.ardetail = (string)dtrPrize[dtrPrize.GetOrdinal("ardetail")];
prize.endetail = (string)dtrPrize[dtrPrize.GetOrdinal("endetail")];
prize.image = (string)dtrPrize[dtrPrize.GetOrdinal("image")];
prize.theme = (string)dtrPrize[dtrPrize.GetOrdinal("theme")];
prize.price = (int)dtrPrize[dtrPrize.GetOrdinal("price")];
prize.audience = (int)dtrPrize[dtrPrize.GetOrdinal("audience")];
prize.type = (byte)dtrPrize[dtrPrize.GetOrdinal("type")];
prize.status = (byte)dtrPrize[dtrPrize.GetOrdinal("status")];
prize.voucher = (string)dtrPrize[dtrPrize.GetOrdinal("voucher")];
prize.supplierid = (int)dtrPrize[dtrPrize.GetOrdinal("supplierid")];
prize.created = (DateTime)dtrPrize[dtrPrize.GetOrdinal("created")];
prize.updated = (DateTime)dtrPrize[dtrPrize.GetOrdinal("updated")];
return prize;
}
Healthy-ish; personally I'd say the unhealthy bit is the bit where it makes use of DataSet and DataAdapter, but that is perhaps just my personal bias.
Yes, you should dispose the adapter etc here (which is what the using does for you, obviously).
As a trivial pointless tidy, you can stack the usings - just makes it a little less verbose:
using (SqlConnection con = new SqlConnection(ConStr))
using (SqlCommand cmd = con.CreateCommand())
{
It will be enough to leave just the first using (the one on the Connection) because disposing the connection will dispose everything you need disposed.
However, there is no harm disposing everything, just a bit more code.

the perfect way to connect to database?

public class SqlHelper
{
public SqlHelper()
{
}
public static SqlConnection GetConnection()
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = #"Data Source=.\SQLEXPRESS;AttachDbFilename=" + System.Web.HttpContext.Current.Server.MapPath(#"~\App_Data\learn.mdf") + ";Integrated Security=True;User Instance=True";
return conn;
}
public static SqlDataReader ExecuteReader(string sql)
{
SqlConnection con = GetConnection();
con.Open();
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataReader dr = null;
try
{
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch
{
con.Close();
return null;
}
return dr;
}
public static Object ExecuteScalar(string sql)
{
SqlConnection con = GetConnection();
con.Open();
SqlCommand cmd = new SqlCommand(sql, con);
Object val = null;
try
{
val = cmd.ExecuteScalar();
}
catch
{
con.Close();
return null;
}
finally
{
con.Close();
}
return val;
}
public static DataSet ExecuteDataSet(string sql)
{
SqlConnection con = GetConnection();
SqlCommand cmd = new SqlCommand(sql, con);
DataSet ds = new DataSet();
SqlDataAdapter adapt = new SqlDataAdapter(cmd);
try
{
adapt.Fill(ds);
}
catch
{
con.Close();
}
return ds;
}
public static void ExecuteNonQuery(string sql)
{
SqlConnection con = GetConnection();
con.Open();
SqlCommand cmd = new SqlCommand(sql, con);
try
{
cmd.ExecuteNonQuery();
}
finally
{
con.Close();
}
}
}
This is the Class which I use to implement every access to my database . But I think that the way I do connection with the database is a little bit overblown cause I have to hit the Connect function every time I need something . As well as other users going to do the same which kills the performance.
So what is the perfect way to connect with the database - and to stay connected if that better . Note that I use the database in many pages!
Thanks
First, you should be using "using" statements to ensure that all your ADO.NET objects are properly disposed of in the event of a failure:
public static void ExecuteNonQuery(string sql)
{
using(var con = GetConnection())
{
con.Open();
using(var cmd = new SqlCommand(sql, con))
{
cmd.ExecuteNonQuery();
}
}
}
However, having said that, I don't really see a problem with this approach. The advantage is that the connections, commands, adapters and whatnot are properly disposed of every time you execute a bit of SQL. If you were to make a single static SqlConnection instance, you'd escalate the chances that the connection is already in use (when, for example, iterating over the contents of a SqlDataReader).
If you are really concerned about it, provide overloads that take a connection as an extra parameter:
public static void ExecuteNonQuery(string sql, SqlConnection connection)
{
using(var cmd = new SqlCommand(sql, con))
{
cmd.ExecuteNonQuery();
}
}
This way, callers can either execute a bit of SQL that doesn't require multiple calls, or they can call your GetConnectionMethod to obtain a connection, and pass it to multiple calls.
If this is used for a web site then you have to consider that between requests for pages, even from the same browser, your server state will be torn down (in general terms) so there's nothing really to be gained from trying to maintain your SQL connection between pages. That's the first thing.
If each page is the result of a single database connection then you are probably as optimised as you really need to be, if you are making several connections over the generation of a page then you may want to look at keeping a connection alive until you have finished retrieving data; either by maintaining the connection or optimising your data retrieval to limit the back and forth between your app and the db.
Maintaining a database connection is the job of the connection pool, and not the connection consumer. The best practice is to aquire a connection as late as possible and release it as soon as possible.
using(var connection = new SqlConnection(YourConnectionStringHelperFunction())
{
}
One thing that YOu might take into consideration is the Dependency Injection PAttern and some IoC controller. If every page needs to have this connection make this an injectable property (constructor probably wont work unless You implement some kind of infrastructure classes like Request) use some container (Unity, Castle, StructureMap) pack the needed things up (maybe cache, maybe some other things) and let the container do the magic (by magic I mean tons of boilerplate code) for You.
luke
First you can write a seperate class like this :
Get method for getting data (with a Select query) and Set method for manipulating data (Insert, Update, Delete)
using System.Data;
using System.Data.Odbc;
using System.Data.SqlClient; //using this you can replace instead odbc to sql
// Example SqlCommand, SqlDataAdapter
class DataBaseConnection
{
private OdbcConnection conn1 = new OdbcConnection(#"FILEDSN=C:/OTPub/Ot.dsn;" + "Uid=sa;" + "Pwd=otdata#123;"); //"DSN=Ot_DataODBC;" + "Uid=sa;" + "Pwd=otdata#123;"
//insert,update,delete
public int SetData(string query)
{
try
{
conn1.Open();
OdbcCommand command = new OdbcCommand(query, conn1);
int rs = command.ExecuteNonQuery();
conn1.Close();
return rs;
}
catch (Exception ex)
{
conn1.Close();
throw ex;
}
}
//select
public System.Data.DataTable GetData(string sql)
{
try
{
conn1.Open();
OdbcDataAdapter adpt = new OdbcDataAdapter(sql, conn1);
DataTable dt = new DataTable();
adpt.Fill(dt);
conn1.Close();
return dt;
}
catch (Exception ex)
{
conn1.Close();
throw ex;
}
}
}
in your form you can make object to that database connection class
DataBaseConnection db = new DataBaseConnection();
now you cal call get set with your get set method as following
string sqlSpecialHoliyday = "SELECT * FROM Holiday WHERE Date_Time='" + selectdate + "' AND IDH='50'";
DataTable dtAdditionalholily = db.GetData(sqlSpecialHoliyday);
AD you can Set Data Using Set method
string insertloginlog = "INSERT INTO Login_Log (Service_No, Machine_Name) VALUES ('" + serviceID + "','" + machiname + "')";
int ret = db.SetData(insertloginlog);
Hope This will help!

Passing sql statements as strings to mssql with C#?

This is a really, really stupid question but I am so accustomed to using linq / other methods for connecting and querying a database that I never stopped to learn how to do it from the ground up.
Question: How do I establish a manual connection to a database and pass it a string param in C#? (yes, I know.. pure ignorance).
Thanks
using (SqlConnection conn = new SqlConnection(databaseConnectionString))
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "StoredProcedureName";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#ID", fileID);
conn.Open();
using (SqlDataReader rdr =
cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
if (rdr.Read())
{
// process row from resultset;
}
}
}
}
One uses the SqlCommand class to execute commands (either stored procedures or sql) on SQL Server using ado.net. Tutorials abound.
Here's an example from http://www.csharp-station.com/Tutorials/AdoDotNet/Lesson07.aspx
public void RunStoredProcParams()
{
SqlConnection conn = null;
SqlDataReader rdr = null;
// typically obtained from user
// input, but we take a short cut
string custId = "FURIB";
Console.WriteLine("\nCustomer Order History:\n");
try
{
// create and open a connection object
conn = new
SqlConnection("Server=(local);DataBase=Northwind;Integrated Security=SSPI");
conn.Open();
// 1. create a command object identifying
// the stored procedure
SqlCommand cmd = new SqlCommand(
"CustOrderHist", conn);
// 2. set the command object so it knows
// to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which
// will be passed to the stored procedure
cmd.Parameters.Add(
new SqlParameter("#CustomerID", custId));
// execute the command
rdr = cmd.ExecuteReader();
// iterate through results, printing each to console
while (rdr.Read())
{
Console.WriteLine(
"Product: {0,-35} Total: {1,2}",
rdr["ProductName"],
rdr["Total"]);
}
}
finally
{
if (conn != null)
{
conn.Close();
}
if (rdr != null)
{
rdr.Close();
}
}
}
3 things no one else has shown you yet:
"Stacking" using statements
Setting an explicit parameter type rather than letting .Net try to pick one for you
"var" keyword
.
string sql = "MyProcedureName";
using (var cn = new SqlConnection(databaseConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ParameterName", SqlDbType.VarChar, 50)
.Value = "MyParameterValue";
conn.Open();
using (SqlDataReader rdr =
cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
if (rdr.Read())
{
// process row from resultset;
}
}
}

Categories