Best method to connect to SQL Server in C# WPF - c#

I'm a beginner.
I already found a way to connect to SQL SERVER using the codes below:
private void getListBtn_Click(object sender, RoutedEventArgs e)
{
SqlConnection con = new SqlConnection("Data Source=.;Initial Catalog=myDB;Integrated Security=true;");
SqlDataAdapter sda = new SqlDataAdapter("SELECT ID,Date,Name,City FROM Info;", con);
DataTable dt = new DataTable();
sda.Fill(dt);
dataGridForm.ItemsSource = dt.DefaultView;
I also wanted to get number of rows from a TABLE and set it to a label, But it's not a good idea to copy and paste this code again, I want to have a method for sqlconnection so i won't rewrite this code again and again for every single query.
Sorry i'm an absolute beginner, 3 days since i started learning C# WPF.

Yes some frameworks and/or ADO's solutions are good and maybe the best "professionnal" approch, you say you're a beginner and I was it not so far ;-).
So the simpliest way is to add a new class for the sql connection. In example add a Sqlconnect.cs class.
using System.Data.SqlClient;
public class Sqlconnect
{
public SqlConnection Con { get; set; }//the object
private string conString { get; set; }//the string to store your connection parameters
}
This class will have a method to open the connection and one to close it.
public void conOpen()
{
conString = "Data Source=..."; //the same as you post in your post
Con = new SqlConnection(conString);//
try
{
Con.Open();//try to open the connection
}
catch (Exception ex)
{
//you do stuff if the connection can't open, returning a massagebox with the error, write the error in a log.txt file...
}
}
public void conClose()
{
Con.Close();//close the connection
}
In your other(s) classe(s) where you need a sql query you first instantiate an new object.
private void getListBtn_Click(object sender, RoutedEventArg e)
{
Sqlconnect con = new Sqlconnect();//instantiate a new object 'Con' from the class Sqlconnect.cs
con.conOpen();//method to open the connection.
//you should test if the connection is open or not
if(con!= null && con.State == ConnectionState.Open)//youtest if the object exist and if his state is open
{
//make your query
SqlDataAdapter sda = new SqlDataAdapter("your query", con);
//etc
con.conClose();//close your connection
}
else
{
//the connection failed so do some stuff, messagebox...as you want
return;//close the event
}
}
this example need some ameliorations, it's evident but I wrote it like this to be clearest.

First thing this is not related to WPF, this is general coding even I would not consider this to be related to .net.
For your current problem to show the count, you dont have to make a call again. You can get the count from the datatable row count. But, I would suggest few things:
You should have one or different separate layers like business, data access etc. as per your needs.
You should not give the connection as the way you have provided here.
You can choose to use any ORMs like entity framework, NHibernate etc based on your needs. This just a direction, you can choose to stick with ADO.Net as you have it your choice. But I would definitely suggest to throw in more layers to avoid duplicate codes and more structured approach.

Best choice if you don't need so much performance is ORM like Entity Framework.
Here is something of basics.
Just use it like in MVC app.

If we copy paste your code, then the error is appearing. I have corrected it and maybe others don't need to struggle like me to find this. :)
// Object exists and State is open
if (Conex != null && Conex.Con.State ==
System.Data.ConnectionState.Open)
{
// Create a String to hold the query
string query = "insert into Xray_Table values
(25,'zzz','hij',3,'uuu',6,'2012-06-18
10:34:09.000')";
// Create a SqlCommand object and pass the constructor the connection string and the query string
SqlCommand queryCommand = new SqlCommand(query, Conex.Con);
// Execute the query to update to the database
queryCommand.ExecuteNonQuery();
// method to close the connection.
Conex.conClose();
}

Related

How to make a DataReader for global use

I have this code in my SQL Connect class.
public class SqlConnect
{
public string connectionString = ConfigurationManager.ConnectionStrings["cn"].ConnectionString;
private SqlConnection con;
public SqlCommand cmd;
private SqlDataAdapter sda;
private DataTable dt;
private SqlDataReader sdr;
public SqlConnect()
{
con = new SqlConnection(connectionString);
con.Open();
}
public void SqlQuery(string queryTxt)
{
cmd = new SqlCommand(queryTxt, con);
}
public DataTable QueryEx()
{
sda = new SqlDataAdapter(cmd);
dt = new DataTable();
sda.Fill(dt);
con.Close();
return dt;
}
public void NonQueryEx()
{
cmd.ExecuteNonQuery();
con.Close();
}
public void Reader()
{
sdr = cmd.ExecuteReader();
while(sdr.Read())
{
for (int i = 0; i < sdr.FieldCount; i++) ;
}
return;
}
Now, in my button I have this code. I'm having error saying cannot convert from Void to Object.
con = new SqlConnect();
con.SqlQuery("Select Department from Salary");
cboDept.Items.Add(con.Reader());
My question is how can I make this run? when I use the public datatable QueryEx I can only get the column name appear on the combobox (just the Column name). I'm searching here but I cant find any solution. How to make this code run?
You're looking for the DisplayMember and ValueMember properties.
Also, it's generally a bad practice to try to and manage your connection like this as it can potentially lead to leaked connections. In a WinForms environment, it's not as dangerous as it is in a web environment, but it is something to be cognizant of, especially if you have lots of WinForms clients talking to the same database. If you have an exception that is thrown in your NonQueryEx method from your code above and caught at a higher level, your SqlConnection will be left open.
See: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql-server-connection-pooling?redirectedfrom=MSDN
The way you want to make your database calls is to wrap your construction of your SqlConnection object in a using block:
Example:
using (var cn = new SqlConnection(connectionString))
{
var cmd = new SqlCommand(...);
cmd.ExecuteNonQuery();
}
If you're wanting to use an abstraction layer to save yourself from typing, wrap your call within a using block within that layer. This is the #1 mistake that I see with ADO.Net code at new clients (in other words, this is an incredibly common mistake and don't let this criticism discourage you). ADO.Net manages connections behind the scenes. Opening and closing a connection does not actually terminate a connection to a database, it releases it to the pool so the next call to .Open or .Close can reuse that same connection. Holding onto it for any longer than necessary means that new connections may need to be created. Likewise, there is no guarantee when your SqlConnect() instances will be cleaned up by .Net, so if you have a repeated exception that is caught at a higher level, this can result in multiple connections waiting to be released until your SqlConnect class is garbage collected.

SQL Connection/Command proper management (to avoid table LOCKS)?

I'm setting up a connection factory for a .NET project, and I'd like to ask what is the best way for it.
I have an issue with the previous Log class not being able to write the logs properly because of table LOCKS (or so they say), so I'm tasked with setting up a new data layer that (hopefully) solves this along some other minor issues.
For now, the code:
public sealed class ConnectionFactory
{
//Will be SQL only
private static SqlConnection sqlConnection = null;
private static string connectionString = ConfigurationManager.ConnectionStrings["Development"].ConnectionString;
public static SqlConnection GetConnection()
{
if(sqlConnection == null)
{
sqlConnection = new SqlConnection();
sqlConnection.Open();
}
return sqlConnection;
}
}
I'll be using mostly procedures, but may have one or another weird request and we'll type a query if needed, so I'm think I have to add a SqlCommand somehow:
private static SqlCommand sqlCommand = null;
public static SqlCommand GetCommand()
{
//Check if sqlConnection is not null (omitted)
if(sqlCommand == null)
{
sqlCommand = sqlConnection.CreateCommand();
}
return sqlCommand;
}
However, should this command be static? Or should I create a new one each time a new query is going to be executed?
Thinking in avoiding locks mostly, can it be caused by having multiple commands or only multiple connections? How do I avoid and deal with this properly?
I believe a "nolock" would work in this case...
FROM [table] with (nolock)
whenever you do a direct query.

Proper way of getting a data from an Access Database

I'm a bit confused of how to get a data from an access database. Is it proper to gather it first in a List then get those data from your List OR it is okay to just directly get it in you database ?
My codes work perfectly fine, but I wanna know if there is a better way to do this?? :
private void button3_Click(object sender, EventArgs e)
{
OleDbConnection connection = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\redgabanan\Desktop\Gabanan_Red_dbaseCon\Red_Database.accdb");
connection.Open();
OleDbDataReader reader = null;
OleDbCommand command = new OleDbCommand("SELECT * from Users WHERE LastName='"+textBox8.Text+"'", connection);
reader = command.ExecuteReader();
listBox1.Items.Clear();
while (reader.Read())
{
listBox1.Items.Add(reader[1].ToString()+","+reader[2].ToString());
}
connection.Close();
*I'm getting my records directly from a database then display it in a listbox.
One thing that is sticking out like a sore thumb is the SQLInjection and to use Parameterised queries, eg:
OleDbCommand command = new OleDbCommand("SELECT * from Users WHERE LastName='#1'", connection);
command.Parameters.AddWithValue("#1", textBox8.Text)
What your doing is perfectly acceptable, although you would generally be better off to use a SQL Database.
Edit:
Here is how you seperate your business logic from the GUI:
Class BusLogic
{
public List<string> ListboxItems = new List<string>();
public void PopulateListBoxItems(string userName)
{
string connString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\redgabanan\Desktop\Gabanan_Red_dbaseCon\Red_Database.accdb";
using (OleDbConnection connection = new OleDbConnection(connString))
{
connection.Open();
OleDbDataReader reader = null;
OleDbCommand command = new OleDbCommand("SELECT * from Users WHERE LastName='#1'", connection);
command.Parameters.AddWithValue("#1", userName)
reader = command.ExecuteReader();
while (reader.Read())
{
ListboxItems.Add(reader[1].ToString()+","+reader[2].ToString());
}
}
}
}
GUI
private void button3_Click(object sender, EventArgs e)
{
var busLogic = new BusLogic();
busLogic.PopulateListBoxItems(textBox8.Text);
\\listBox1.Items.Clear();
ListboxItems.DataSource = busLogic.ListboxItems;
}
The beauty of this "MVC" approach is that we only really need to test the BusLogic if we rely on controls being bound using Binding.
ps Ideally ListboxItems would be an IEnumerable instead of List so that we don't expose any functionality to Add/Remove etc from the caller. This is good API design.
I would say the answer is "yes" to both.
What you're doing now is perfectly acceptable for simple cases. Just be aware that it doesn't "scale" very well. That is, loading 10 or 20 items is fine. But what happens if it becomes 10 thousand or a million?
In that case you want to look at using a Model-View-Controller (MVC) architecture. That's a topic in itself, but basically you decouple the listbox (the "view") from the data (the "model").
See this site for a C#-centric MVC discussion
In between what you're doing now and a full-blown MVC architecture, you may simply want to do as you suggest - load the list first then add them to the list box. That gains you nothing if you just load it once, but if the list is loaded "all over the place", you can save the database IO overhead each time by just accessing it once.
The fact that you thought to ask the question indicates you're on the right track.
Although your code works without any problem, I suggest you to perform some exception handling as in this example, since both OleDbConnection.Open() and OleDbCommand.ExecuteReader() might throw an InvalidOperationException.
It is also common to wrap the connection with a using statement, so in the end connection.close() is called automatically, but this is just a personal preference.
You can maybe separate your data access functions in different classes or create generic functions to retrieve records.

How to create an sqlconnection in a class with c# to use in all form?

Create sqlserver connection in class
call connection class to use all form.
I want to create SQLServer connection in class with C# to use all forms.
Hereabout code of connection in class file
public System.Data.SqlClient.SqlConnection Con = new System.Data.SqlClient.SqlConnection();
public System.Data.SqlClient.SqlCommand Com = new System.Data.SqlClient.SqlCommand();
public string conStr;
public SQL2(string conStr)
{
try
{
Con.ConnectionString = conStr;
Con.Open();
Com.Connection = Con;
Com.CommandTimeout = 3600;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public bool IsConnection()
{
Boolean st;
if (Con.State==ConnectionState.Open)
{
st=true;
}
else
{
st = false;
}
return st;
}
Can give me full example code?
What you probably want is a factory that you use to use to create a connection:
using(var connection = databaseConenctionFactory.Create())
{
// then do want you want here
}
As LarsTech mentioned you don't want to keep open connections. Open/Use/Close. The using syntax is rather useful here as it takes care of all the unnecessary fluff. So once you are in a habit of using using you will not run into any weird behaviour in production systems.
There is quite a bit around implementing something like this so you could do some research. You could make use of the ADO Provider Factories and use IDbConnection instead of a specific implementation to abstract you implemetation.
You could also usse dependency injection to get to you factory/factories.
So choose your poison :)

commonly integrate a line of code at many places in c#

OK here my piece of code
MySqlConnection conn = new MySqlConnection("Userid=root;pwd=root;port=3306;host=localhost;database=test");
conn.Open();
Due to some issue with the new version of the devart connector i'm using i have to add a line of code OldCompatibility.BinaryAsString = true;
everywhere in my code as shown below
OldCompatibility.BinaryAsString = true;
MySqlConnection conn = new MySqlConnectio("User id=root;pwd=root;port=3306;host=localhost;database=test");
conn.Open();
But the problem is i have to make this change all over my application which have many pages with this piece of code.So is there any way to do this globally so that i dont have to make this change all over my application.
i'm using devart connector 6
Assuming that your connection is remotely similar each time; don't. Keep all your connection logic in one shared method, and use that instead of repeating the connection code everywhere.
public static MySqlConnection Connect() {
OldCompatibility.BinaryAsString = true;
MySqlConnection conn = new MySqlConnection("User id=root;pwd=root;port=3306;host=localhost;database=test");
conn.Open();
return conn;
}
MySqlConnection is your custom class if you put OldCompatibility.BinaryAsString = true in the constructor of MySqlConnection then it would work
Change all your code at once with find and replace using regular expressions:
1.- Hit Ctrl+H to open the “Find and Replace” window Enter your search, replace line breaks with “\n” (no quotes)
2.- Expand “Find options” and check “Use”, select “Regular Expressions” (this also activates the right arrow next to the “Find what” box. It lists a few commands/shortcuts).
For example:
Type this on find:
{MySqlConnection conn = new MySqlConnection}
Then try this on replace:
OldCompatibility.BinaryAsString = true;\n\t\t\1 MySqlConnection conn = new MySqlConnection
This will find all the code that matches the search and add an additional line infront of it. Notice the place holder {...} being replaced with \1
You can use a factory method
public class FactoryMethods
{
public static MySqlConnection GetConfiguredConnection()
{
OldCompatibility.BinaryAsString = true;
MySqlConnection conn = new MySqlConnectio("User id=root;pwd=root;port=3306;host=localhost;database=test");
conn.Open();
return conn;
}
}
And assuming the connection is IDispose-able
using (var myConn = FactoryMethods.GetConfiguredConnection())
{
// Use your connection here
}
You should really consider #minitech's suggestion on using a method, but if you really can't change the code anywhere, there are only really two options I can see;
Extend MySQLConnection to a new class using the same name in another namespace, just changing the constructor to include your line. Then replace only the using line at the top of the file.
If that can't be done, implement a wrapper class in the same manner.
Both these options may fail to work (#1 if the class is final for example, and #2 if the class is passed as a parameter to any functions), but unless you can at least do a global search/replace or implement #minitech's suggestion with a method, I can't see any other way.

Categories

Resources