I'm developing an application in C# (but this is not relevant, since i don't want to use any language facility) and I need to handle the connection to a database. I would avoid to explicitly create the connection in each method, like:
private void btnAnteprima_Click(object sender, EventArgs e)
{
SqlConnection myConnection = new SqlConnection("user id=***;" +
"password=***;server=***;" +
"database=***");
myConnection.Open();
SqlDataReader myReader = null;
SqlCommand myCommand = new SqlCommand("select * from *** where IDCliente=*", myConnection);
myReader = myCommand.ExecuteReader();
while (myReader.Read())
{
MessageBox.Show(myReader["xyz"].ToString());
}
}
I would something like:
private void btnAnteprima_Click(object sender, EventArgs e)
{
SqlReader myReader = DbFactory.ExecuteQuery("select * from *** where IDCliente=*");
while (myReader.Read())
{
MessageBox.Show(myReader["xyz"].ToString());
}
}
As far as I know, the use of singleton pattern is useless or even harmfull in terms of performance. I wander about factory pattern to achieve this but i can't figure out how to do at its best. Did you have examples, paper to do this? I don't want reinvent the wheel, I just want use the right design pattern, and understand what's behind the wheel.
Take a look at the Data Access Block with the Microsoft Enterprise Library.
http://msdn.microsoft.com/en-us/library/ff664408(v=pandp.50).aspx
Related
I am new to C# and I am using windows forms.
I am building an application and I am facing a strange serious problem when Form loads.
I have 2 forms:
Form1 has a button_Edit and DataGridView
Form2 has a DataGridView1 and DataGridView2
As it is shown in the code and the screen shot, in Form1 when I select a row in DataGridView then click on Button_Edit the Order number and DateTime values in DataGridView on Form1 are passed to Form2 and then Form2 opens up.
Now in Form2 Load event there is a SQL query which takes Order number and DateTime to bring the relevant order details and then fill DataGridView1 and DataGridView2 in Form2.
In Form1:
Form2 frm2 = new Form2();
private void button_Edit_Click(object sender, EventArgs e)
{
frm2._ Order_Number= Convert.ToInt32(dataGridView1.SelectedRows[0].Cells[0].Value);
frm2._ Date_Time= Convert.ToDateTime(dataGridView1.SelectedRows[0].Cells[4].Value);
frm2.ShowDialog();
}
In Form2:
SqlConnection MyConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
SqlCommand MyCommand = new SqlCommand();
DataTable DataTable = new DataTable();
SqlDataAdapter Sql_Data_Adapter = new SqlDataAdapter();
int Order_Number;
DateTime Date_Time;
int i;
double Sum;
int RowIndex;
public int _ Order_Number
{
set { Order_Number = value; }
}
public DateTime _ Date_Time
{
set { Date_Time = value; }
}
private void Form2_Load(object sender, EventArgs e)
{
DataTable.Rows.Clear();
DataTable.Columns.Clear();
MyConnection.Open();
MyCommand.CommandText = "SELECT * FROM Customer_Order_Details WHERE Order_Number = #OrderNumber and Date_Time = #DateTime ";
MyCommand.Connection = MyConnection;
MyCommand.Parameters.Add("#OrderNumber", SqlDbType.Int).Value = Order_Number;
MyCommand.Parameters.Add("#DateTime", SqlDbType.DateTime).Value = Date_Time;
Sql_Data_Adapter.SelectCommand = MyCommand;
Sql_Data_Adapter.Fill(DataTable);
MyCommand.Parameters.Clear();
MyConnection.Close();
dataGridView1.Rows.Clear();
dataGridView2.Rows[0].Cells[1].Value = 0;
Sum = 0;
//////////////FILL THE ORDER INTO DATAGRIDVIEW1///////////
RowIndex = DataTable.Rows.Count - 1;
for (i = 0; i <= RowIndex; i++)
{
dataGridView1.Rows.Add(DataTable.Rows[i][2], DataTable.Rows[i][3], DataTable.Rows[i][4]);
// Calculate the total:
Sum = Convert.ToDouble(DataTable.Rows[i][4]) + Sum;
}
dataGridView2.Rows[0].Cells[1].Value = sum;
}
The issue:
This code works fine and as I wanted and DataGridView1 & DataGridView2 in Form2 are filled with the right details and it works fine when Form2 loads.
However, sometimes Form2 freezes after filling both DataGridView1 & DataGridView2 when Form2 loads and I can not do anything until I kill the Application using Task manager.
This issue happens sometimes and it is unpredictable. I really don’t know what is wrong.
I had a look here , here and here but non of those questions related to my issue. Note that I already use try catch and it does not throw anything because the form freezes. This freeze behavior occurs in the release mode I mean after I build EXE file then I install it in a PC and here the issue happens.
Has anyone got any idea why this bad unpredictable behavior occurs?
Is there anything that I should change in my code?
I will be very happy to listen to any new ideas/solutions no matter how small it is, it will be very beneficial.
Thank you
Do SQL work on another thread. Check out Asynchronous call.
BeginInvoke
I suggest using Async versions of Open (connecting to RDBMS) and ExecuteReader (query executing):
con.Open() -> await con.OpenAsync()
q.ExecuteReader() -> await q.ExecuteReaderAsync()
this easy substitution makes UI responsible (it doesn't freeze) while connecting to RDBMS and executing the query.
// do not forget to mark Form2_Load method as async
private async void Form2_Load(object sender, EventArgs e) {
// Do not share the connection - create it and dispose for each call
using (SqlConnection con = new SqlConnection(...)) {
await con.OpenAsync();
string sql =
#"SELECT *
FROM Customer_Order_Details
WHERE Order_Number = #OrderNumber
AND Date_Time = #DateTime";
// do not share command/query as well
using (SqlCommand q = new SqlCommand(sql, con)) {
q.Parameters.Add("#OrderNumber", SqlDbType.Int).Value = Order_Number;
q.Parameters.Add("#DateTime", SqlDbType.DateTime).Value = Date_Time;
dataGridView1.Rows.Clear();
dataGridView2.Rows[0].Cells[1].Value = 0;
Sum = 0;
// We actually don't want any sql adapter:
// all we have to do is to fetach data from cursor and append it to grids
using (var reader = await q.ExecuteReaderAsync()) {
while (reader.Read()) {
dataGridView1.Rows.Add(reader[2], reader[3], reader[4]);
Sum += Convert.ToDouble(reader[4]);
}
}
}
}
}
as said the code snippet you gave us isn't well written. You should use more Try/Catch Statements to prevent crashs and freezes on your programm. This will help you to find bugs even while running the Programm in release. Furthermore you have many options to solve your problem.
1:
Try to start Form2 in a second thread, then only your form2 will freeze until your sql finishes
2:
As mentioned before try to use asyncronous calls to avoid freeze time of handling the sql
3:
There is no direct need of a SQL Database/Connection. You could also use a Collection and create objects defined of your Products (like cola) and them bind them through the database. (If you are interested in i could show you a example)
The best way for you would be:
Add some Try/Catch Statements and get familiar with it, get familiar with Systems.Thread and try to start your form2 in a new thread if this doenst work go to step 2 and add asynchronus calls
In the end i would like to tell you, that namen your Forms "Form1" and "Form2" isn't nice could maybe you like to change it.
Today I started learning about SqlDependency and all of it's features and I have slowly been testing it on my WCF Service. I've got everything working so far by following a couple of tutorials, but I got stuck at a very crucial point.
My issue is (and I know that I DO NOT understand the whole SqlDependency concept yet), that for the life of me cannot figure out how to send my client-side WPF application a callback from my WCF service after the OnChange event has been triggered. I might be wording everything wrong in my question, so please excuse me.
Here I start my SqlDependency:
private string dependencyResult = "";
public void StartListener()
{
SqlDependency.Stop(ConfigurationManager.ConnectionStrings["TruckDbWcf"].ConnectionString);
SqlDependency.Start(ConfigurationManager.ConnectionStrings["TruckDbWcf"].ConnectionString);
RegisterDependency();
}
Here is my RegisterDependency method:
public void RegisterDependency()
{
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["TruckDbWcf"].ConnectionString);
SqlCommand command = new SqlCommand();
command.Connection = connection;
command.Connection.Open();
command.CommandType = CommandType.Text;
command.CommandText = "SELECT [Id], [Title] FROM [dbo].[Feeds];";
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += SqlDependencyOnChange;
command.ExecuteReader();
command.Connection.Close();
}
And my OnChange event:
private void SqlDependencyOnChange(object sender, SqlNotificationEventArgs eventArgs)
{
SqlDependency dependency = sender as SqlDependency;
dependency.OnChange -= SqlDependencyOnChange;
StartListener();
}
I want to call my StartListener() method from my WPF app, so I use an
[OperationContract]
void StartListener();
And I call the method from my WPF application like so from a button click event:
service.StartListenerAsync();
So my question is: How would I be possible to get a notification/message/callback from my service to let me know that data in my dbo.Feeds table has changed? I have no clue how to do this and I feel a bit stupid that I cannot figure this out at the moment. Can someone please help me?
I want to show a message in a label in my WPF application that there has been a change in data.
Edit - I also have enabled the Service Broker and set the required permissions in my database.
I used Detecting Changes with SqlDependency as example for the code that I'm writing. I've also looked at other links with similar code, but none of them work.
Essentially, I simply want to change label1.Text when a change has been made to table [ErrorLog]. For some reason, OnDependencyChange is not firing.
I've enabled Service Broker in the database:
ALTER DATABASE TestDB
SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE
Now, here's my complete code. It's very short:
public partial class Form1 : Form
{
private string GetConnectionString()
{
return #"Data Source=USER-PC\SQLEXPRESS;Initial Catalog=TestDB;Persist Security Info=True;User ID=TestUser;Password=12345;";
}
SqlConnection connection;
public Form1()
{
InitializeComponent();
connection = new SqlConnection(GetConnectionString());
connection.Open();
SqlDependency.Start(GetConnectionString());
i = 0;
}
int i;
void OnDependencyChange(object sender, SqlNotificationEventArgs e)
{
i++;
label1.Text = "Changed: " + i.ToString();
// Handle the event (for example, invalidate this cache entry).
}
void SomeMethod()
{
// Assume connection is an open SqlConnection.
// Create a new SqlCommand object.
using (SqlCommand command =
new SqlCommand("SELECT [ErrorLog].[ID],[ErrorLog].[Project],[ErrorLog].[Form],[ErrorLog].[Message],[ErrorLog].[Exception],[ErrorLog].[InsertDate] " +
"FROM [dbo].[ErrorLog]", connection))
{
// Create a dependency and associate it with the SqlCommand.
SqlDependency dependency = new SqlDependency(command);
// Maintain the reference in a class member.
// Subscribe to the SqlDependency event.
dependency.OnChange += new OnChangeEventHandler(OnDependencyChange);
// Execute the command.
using (SqlDataReader reader = command.ExecuteReader())
{
// Process the DataReader.
}
}
}
}
I checked if service broker is enabled and it is; the following returns 1:
SELECT is_broker_enabled
FROM sys.databases
WHERE name = 'TestDB';
Any help is appreciated.
Thanks.
You are doing everything correctly except one thing. Call the method SomeMethod() once in your Form1 constructor.
All subsequent changes to your table data will trigger the dependency change.
Can anyone explain why an SqlDataAdapter is used in the following code? The code is working fine without this adapter.
Also, why do we use DataAdapter? Please help me to understand this DataAdapter usage.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
private void button1_Click(object sender, EventArgs e)
{
try
{
SqlConnection con = new SqlConnection("Data Source=.....\\SQLEXPRESS;Initial Catalog=......;Integrated Security=True");
con.Open();
SqlDataAdapter da =new SqlDataAdapter(); // Why use `SqlDataAdapter` here?
SqlCommand sc = new SqlCommand("insert into bhargavc values(" + textBox1.Text + "," + textBox2.Text + ");", con);
var o = sc.ExecuteNonQuery();
MessageBox.Show(o + "record to be inserted");
con.Close();
}
catch (Exception)
{
MessageBox.Show("error in the code");
}
}
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}
Data adapter works like a mediator between the database and the dataset. However, a data adapter cant store data. It just gives data from the database to the dataset.
For Example:
A water pipe is used to bring water from a source (well, pond, etc.) to a destination. However, the pipe isn't used to store water. In the same way, a data adapter (like a water pipe) sends data from the database to a dataset.
This should give a clearer understanding about data adapters.
A data adapter is used to read data from a data reader into a DataTable or a DataSet.
As you are not reading any data from the database in this code, the data adapter is completely superflous.
As a side note, you should use parameters instead of putting values directly into the query. Your code is totally open to SQL injection attacks.
There are several reasons to use a DataAdapter:
You can't fill a DataSet without one.
When the adapter completes its .Fill() method, it will close the connection for you; you don't have to explicitly call the .Close() method on your connection object. Although, it is still good practice to.
In your case, it isn't necessary to have one though. But, if you did want to use one, the implementation would look like this:
SqlDataAdapter da = new SqlDataAdapter();
DataSet ds = new DataSet();
da.Fill(ds);
From there, there are further actions that you can take on the ds object like exporting to Excel via Interop, filling a DataGridView or even updating a database table.
To fill either dataset or datatable
You don't have to close your SQL connection explicitly like .Close()
Same as the title and using C#.
Anyone know how to do this? I have a bunch of data read into a list box but the data doesn't refresh unless I restart the windows form. anyone know how to refresh it on a button click event?
{
SqlConnection conn = new SqlConnection();
conn.ConnectionString = (#"Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Users\John\Desktop\DB\DB\DB\setup.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True");
conn.Open();
SqlCommand cmd = new SqlCommand
("SELECT PEOPLE " + "FROM Workers", conn);
try
{
SqlDataReader sdr = cmd.ExecuteReader();
while (sdr.Read())
{
listBox1.Items.Add(sdr["people"].ToString());
}
sdr.Close();
}
catch (SqlException ex)
{
MessageBox.Show(ex.Message);
}
finally
{
conn.Close();
}
}
This is in windows form Load. So i'm looking to add a button on my form which refreshes the listbox items list
Add a Method
private void ShowPeople()
{
// Put your code;
}
and then use the same in your button click
private void Button_Click(object sender,EventArgs e)
{
ShowPeople();
}
To reload data over your sqldatareader (at least I guess you mean set by using the word "refresh") by pressing a button you simply have to access the database again with the same code you are already using. But the important point here is, that you are using a bad design. Therefore I point out an article (30 mins to read) which helped me a lot to improve my code and therefore got rid of code duplication.
Please read: http://imar.spaanjaars.com/416/building-layered-web-applications-with-microsoft-aspnet-20-part-1
After you have read this article I will promise you that you will have a better understanding of how you have to access data in the database within your application