SQL dependency and data refering in SQL - c#

when we work with sql dependency then we need to always refer a sql like below one SELECT ActivityDate FROM [bba-reman].MyLog
i just like to know if i write the above sql this way then does it work
SELECT TOP 1 ActivityDate FROM [bba-reman].MyLog OR
SELECT TOP 5 ActivityDate FROM [bba-reman].MyLog
i am looking for suggestion and guidance.
private void RegisterNotification()
{
string tmpdata = "";
System.Data.SqlClient.SqlDependency.Stop(connectionString);
System.Data.SqlClient.SqlDependency.Start(connectionString);
try
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT ActivityDate FROM [bba-reman].MyLog";
dep = new SqlDependency(cmd);
dep.OnChange += new OnChangeEventHandler(OnDataChange);
SqlDataReader dr = cmd.ExecuteReader();
{
while (dr.Read())
{
if (dr[0] != DBNull.Value)
{
tmpdata = dr[0].ToString();
}
}
}
dr.Dispose();
cmd.Dispose();
}
}
finally
{
//SqlDependency.Stop(connStr);
}
}

According to the SQL Server Books Online (https://msdn.microsoft.com/en-us/library/t9x04ed2.aspx), one of the restrictions for using QueryNotifications is that the statement must not use a TOP expression. SqlDependency is just a higher level implementation of QueryNotifications that takes care of the Service Broker plumbing.

The SqlDependency class has a lot of restrictions as well as the memory leak problems. An absence of the TOP instruction is the one of them. Hovewer, you can use an open source realization of the SqlDependency class - SqlDependencyEx. It uses a database trigger and native Service Broker notification to receive events about the table changes. This is an usage example:
int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME))
{
sqlDependency.TableChanged += (o, e) => changesReceived++;
sqlDependency.Start();
// Make table changes.
MakeTableInsertDeleteChanges(changesCount);
// Wait a little bit to receive all changes.
Thread.Sleep(1000);
}
Assert.AreEqual(changesCount, changesReceived);
With SqlDependecyEx you are able to monitor INSERT, DELETE, UPDATE separately and receive actual changed data (xml) in the event args object. Filtering incoming messages helps you implement desirable behavior. Hope this help.

Related

How to refactor a large class that stores numerous SqlCommands in a Dictionary

I have recently started refactoring an old system designed by someone with little experience in OOP. Thankfully, (nearly) all access to the database are within a single 3000 lines long file. That files contains a Dictionary<string, SqlCommand>, the SqlConnection, a very long function adding every single SQL query to the dictionary like this:
cmd = new SqlCommand(null, _sqlConnection);
cmd.CommanText = "SELECT * FROM User WHERE User.UserID = #id;" // Most queries are far from being this simple
cmd.Parameters.Add(new SqlParameter("#id", SqlDbType.Int, 0));
cmd.Prepare();
_cmds.Add("getUser", cmd);
Those queries are used by functions within that same file that would look like this:
public void deleteUser(int userId)
{
if (_cmds.TryGetValue("deleteUser", out SqlCommand cmd))
{
lock(cmd)
{
cmd.Parameters[0].Value = userId;
cmd.ExecuteNonQuery();
}
}
}
public int isConnected(int userId, out int amount)
{
bool result = false;
amount = 0;
if (_cmds.TryGetValue("userInfo", out SqlCommand cmd))
{
lock (cmd)
{
cmd.Parameters[0].Value = userId;
using (SqlDataReader reader = new cmd.ExecuteReader())
{
if (reader.HasRows)
while (reader.Read())
{
amount = (int)Math.Round(reader.GetDecimal(0));
result = reader.GetInt32(1);
}
}
}
}
return result;
}
Now this is horrible to work with and maintain. I finally have the time to refactor this. I wanted to turn this into a proper DAL with repositories which would be used by services and be dependency injectable.
I don't really care to change the functions or the queries (using a ORM for example). What I'm more interested in is to split the file into many files in a way that would allow me to mock, test and modify it more easily. I'm looking for a way to better structure the existing code, though I know a lot of copy/pasting and recoding will be required.
Would recommend replacing the manually written object-mapping code with using an Object-Relational Mapper like NHibernate, which will save the time and effort of creating and maintaining a data access layer.
Check out Dapper. It is a "micro-ORM" and offers high-performance object-oriented data access. You can continue to use all the existing queries, but replace all the boiler-plate ADO.NET code with Dapper.
This is going to take some repetitive work, but here are a few ideas on how to get a handle on it. This won't put the code in some ideal state, but might make it a little bit more manageable. One challenge is that every method has parts in two places - one in the method and one where the command is stored in the dictionary.
Don't add any more SQL to this class, ever. Begin defining and using the new repositories you want.
Being able to mock it is easy, too. You can use the extract interface refactoring to create an interface so that you can mock this class, even in its current form. That's going to be a big, ugly interface, but at least you can mock methods if you need to.
That's the easy part. How can the entire class be refactored without breaking any one part of it? These steps are just some ideas:
A first step is just to inject the connection string the class needs:
public class YourDataAccessClass
{
private readonly string _connectionString;
public YourDataAccessClass(string connectionString)
{
_connectionString = connectionString;
}
}
You'll use it one method at a time. Initially you can leave most of the class, including the dictionary, as-is. That way the methods you haven't modified will continue to work.
Next, you could open up the class in two separate windows so that you can see the dictionary function that contains the SQL and the functions that use it side-by-side. This will be a lot harder if you have to scroll back up and down.
You'll likely want to move the SQL for each function into that function. You could do this as you refactor each function, but it might be less painful to do it all at once so that you gain efficiency from repetition.
You could define a new variable in each function and copy and paste:
var sql = "SELECT * FROM User WHERE User.UserID = #id;";
(Again, not the way I'd normally write this.)
Now you've got a function or 100 functions that look like this:
public void deleteUser(int userId)
{
var sql = "DELETE User WHERE User.UserID = #id;";
if (_cmds.TryGetValue("deleteUser", out SqlCommand cmd))
{
lock(cmd)
{
cmd.Parameters[0].Value = userId;
cmd.ExecuteNonQuery();
}
}
}
For the non-query commands you could write a function like this in your class which will eliminate the repetitive code to open a connection, create a command, etc:
private void ExecuteNonQuery(string sql, Action<SqlCommand> addParameters = null)
{
using (var connection = new SqlConnection(_connectionString))
using (var command = new SqlCommand(sql))
{
addParameters?.Invoke(command);
connection.Open();
command.ExecuteNonQuery();
}
}
Save the following snippet of code. You might even just be able to keep it in the clipboard most of the time. Paste it into each one of your non-query methods right beneath the SQL:
ExecuteNonQuery(sql, command =>
{
});
After you paste it, move the line or lines that add parameters into the body of the cmd argument (which is named cmd so that you can move the lines without changing the variable name) and then delete the existing code that executed the query previously.
ExecuteNonQuery(sql, cmd =>
{
cmd.Parameters[0].Value = userId;
});
Now your function looks like this:
public void deleteUser(int userId)
{
var sql = "DELETE User WHERE User.UserID = #id;";
ExecuteNonQuery(sql, cmd =>
{
cmd.Parameters[0].Value = userId;
});
}
I'm not saying that's fun, but it will make the process of editing those functions more efficient since you're typing less and just moving things around in exactly the same way over and over.
The ones that actually return data are less fun, but still manageable.
First, take pretty much the same boilerplate code. This could likely be improved because it's still a little repetitive, but at least it's more self-contained:
using (var connection = new SqlConnection(_connectionString))
using (var cmd = new SqlCommand(sql)) // again, named "cmd" on purpose
{
connection.Open();
}
Starting with this:
public int isConnected(int userId, out int name)
{
var sql = "SELECT * FROM User WHERE User.UserID = #id;";'
bool result = false;
amount = 0;
if (_cmds.TryGetValue("userInfo", out SqlCommand cmd))
{
lock (cmd)
{
cmd.Parameters[0].Value = userId;
using (SqlDataReader reader = new cmd.ExecuteReader())
{
if (reader.HasRows)
while (reader.Read())
{
amount = (int)Math.Round(reader.GetDecimal(0));
result = reader.GetInt32(1);
}
}
}
}
}
Paste your boilerplate into the method:
public int isConnected(int userId, out int name)
{
var sql = "SELECT * FROM User WHERE User.UserID = #id;";'
bool result = false;
amount = 0;
using (var connection = new SqlConnection(_connectionString))
using (var cmd = new SqlCommand(sql)) // again, named "cmd" on purpose
{
connection.Open();
}
if (_cmds.TryGetValue("userInfo", out SqlCommand cmd))
{
lock (cmd)
{
cmd.Parameters[0].Value = userId;
using (SqlDataReader reader = new cmd.ExecuteReader())
{
if (reader.HasRows)
while (reader.Read())
{
amount = (int)Math.Round(reader.GetDecimal(0));
result = reader.GetInt32(1);
// was this a typo? The code in the question doesn't
// return anything or set the "out" variable. But
// if that's in the method then that will be part of
// what gets copied.
}
}
}
}
}
Then, just like before, move the part where you add your parameters above connection.Open(); and move the part where you use the command just beneath connection.Open(); and delete what's left. The result is this:
public int isConnected(int userId, out int name)
{
var sql = "SELECT * FROM User WHERE User.UserID = #id;";'
bool result = false;
amount = 0;
using (var connection = new SqlConnection(_connectionString))
using (var cmd = new SqlCommand(sql)) // again, named "cmd" on purpose
{
cmd.Parameters[0].Value = userId;
connection.Open();
using (SqlDataReader reader = new cmd.ExecuteReader())
{
if (reader.HasRows)
while (reader.Read())
{
amount = (int)Math.Round(reader.GetDecimal(0));
result = reader.GetInt32(1);
}
}
}
}
You can probably get into a groove and do these in a minute or two each, which means that it will only take a few hours.
Once all of this is done you can delete your massive dictionary function. Now the class depends on an injected connection string and opens and closes connections normally instead of storing a connection and using it over and over.
You can also break it up. One way is to move the connection string and the helper function into a base class (or just duplicate the helper function - it's really small) and you can move any of the query functions into a smaller class because each function is self-contained.

Is there any way to react on Azure SQL Database changes?

I use SignalR in my application and to react on database changes I've used Sql Dependency
SqlDependency.Start(con);
But I'm getting the following error:
Statement 'RECEIVE MSG' is not supported in this version of SQL Server
So as I understand Azure SQL Database doesn't support Service Broker.
Is there any solution, besides migrating to Azure VM?
Example of code with SQL Dependency:
public class NotificationComponent
{
public void RegisterNotification(DateTime currentTime)
{
string conStr = ConfigurationManager.ConnectionStrings["sqlConString"].ConnectionString;
string sqlCommand = #"SELECT [ContactID],[ContactName],[ContactNo] from [dbo].[Contacts] where [AddedOn] > #AddedOn";
using (SqlConnection con = new SqlConnection(conStr))
{
SqlCommand cmd = new SqlCommand(sqlCommand, con);
cmd.Parameters.AddWithValue("#AddedOn", currentTime);
if (con.State != System.Data.ConnectionState.Open)
{
con.Open();
}
cmd.Notification = null;
SqlDependency sqlDep = new SqlDependency(cmd);
sqlDep.OnChange += sqlDep_OnChange;
using (SqlDataReader reader = cmd.ExecuteReader())
{
}
}
}
void sqlDep_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
SqlDependency sqlDep = sender as SqlDependency;
sqlDep.OnChange -= sqlDep_OnChange;
var notificationHub = GlobalHost.ConnectionManager.GetHubContext<NotificationHub>();
notificationHub.Clients.All.notify("added");
RegisterNotification(DateTime.Now);
}
}
public List<Contact> GetContacts(DateTime afterDate)
{
using (MyPushNotificationEntities dc = new MyPushNotificationEntities())
{
return dc.Contacts.Where(a => a.AddedOn > afterDate).OrderByDescending(a => a.AddedOn).ToList();
}
}
}
You can use the "when an item is created" and the "when an item is modified" triggers for SQL in Azure Logic App to react to data changes.
The SQL connector in Azure Logic Apps uses a polling mechanism to query a table for changes using a TIMESTAMP / ROWVERSION column. This data type is specifically designed for this kind of processing in SQL. The polling query essentially selects all rows where the rowversion is greater than the last polled value. The behavior is reliable since the column is controlled by SQL Server and the performance is extremely fast in the case where there is no new data. When there is new data, the performance is comparable to a simple row query.
For more information, please read this article.

update database using SqlDataAdapter in C#

I have below code to update my database table when button is clicked but it doesn't work.
protected void Button_Click(object sender, EventArgs e)
{
HasinReservation.Entities.Db.Transaction dt = new Transaction();
SqlConnection connection = new SqlConnection(
#"Data Source=192.x.x.x\Sql2008;Initial Catalog=GardeshgariKish;User ID=cms;Password=xxxxx;MultipleActiveResultSets=True;Application Name=EntityFramework");
connection.Open();
SqlCommand sqlCmd = new SqlCommand(
"Update Transaction SET IsCancelled = 1 WHERE BarCodeNumber = #Value1", connection);
SqlDataAdapter sqlDa = new SqlDataAdapter(sqlCmd);
string barcode = dgvData.Rows[0].Cells[12].Text;
sqlCmd.Parameters.AddWithValue("Value1", barcode);
connection.Close();
}
I am troubled by your implementation of Entity Framework but then not using the framework for what it was designed...
You have configured your data adapter and the command, and even opened the connection... but you have not actually executed the command.
sqlCmd.ExecuteNonQuery();
I understand that your actual business logic may have been replaced with this simple CRUD operation, but the main reason that we use the Entity Framework is to avoid writing any T-SQL in our business logic. Why didn't you use the framework to commit the change:
protected void Button3_Click(object sender, EventArgs e)
{
// cancel the selected transaction
string selectedBarcode = dgvData.Rows[0].Cells[12].Text;
using(var dataContext = new HasinReservation.Entities.Db())
{
var transaction = dataContext.Transaction.Single(t => t.Barcode == selectedBarcode);
transaction.IsCancelled = true;
dataContext.SaveChanges();
}
}
This in itself may not be a great solution but it uses the framework to do exactly what you attempted to do manually.
Why are you trying to use a SqlDataAdapter to execute an UPDATE statement? When constructing a SqlDataAdapter with a SqlCommand object, that command object represents the SELECT command for the adapter. An UPDATE statement doesn't select anything, and a SELECT command doesn't update anything.
Get rid of the SqlDataAdapter entirely and just execute the command:
sqlCmd.ExecuteNonQuery();
You'll probably also want to add some error handling so exceptions don't reach the UI (and to ensure the connection is properly closed on error conditions). You also don't seem to be doing anything with that Transaction object, so you can probably get rid of that too.

how to keep sql dependency doing the its purpose

I have a console application.
I wanna keep watching the changes on a specific column in my database table.
I read through internet and I have found that sql dependency is good for my purpose. I started learning about it and I did the following:
create a class.
In the constructor, I called the static function start and I called a function that has all the sql dependency settings.
My problem
When I run the application using the start click on visual studio 2013, the apps works and then stops. However, what I need is that the apps starts working and keep watching for changes in my database's table.
Could you help me please?
Code:
This is a very very simple c# code.
public class MyListener
{
public MyListener()
{
SqlDependency.Start(getConnectionString());
this.listen();
}
private string getConnectionString()
{
return ConfigurationManager.ConnectionStrings["popup"].ConnectionString.ToString();
}
private void listen()
{
string query = "SELECT CallerID FROM TransferToSIP WHERE hasBeenRead = 0";
SqlConnection con = new SqlConnection(getConnectionString());
SqlCommand cmd = new SqlCommand(query, con);
con.Open();
using (cmd)
{
SqlDependency dependency = new SqlDependency(cmd);
dependency.OnChange += new
OnChangeEventHandler(OnDependencyChange);
using (SqlDataReader reader = cmd.ExecuteReader())
{
}
}
}
void OnDependencyChange(object sender, SqlNotificationEventArgs e)
{
Console.WriteLine("Roma");
}
void Termination()
{
SqlDependency.Stop(getConnectionString());
Console.Read();
}
The problem is in absence of the resubscruption. You should call the listen method inside of OnDependencyChange. I know that it is weird, but it is the SqlDependency class.
Be careful using the SqlDependency class to monitor changes in the database tables - it has the problems with the memory leaks. However, you can use your own realization with DDL triggers and SQL Service Broker API or use one of an open source projects, e.g. SqlDependencyEx:
int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME))
{
sqlDependency.TableChanged += (o, e) => changesReceived++;
sqlDependency.Start();
// Make table changes.
MakeTableInsertDeleteChanges(changesCount);
// Wait a little bit to receive all changes.
Thread.Sleep(1000);
}
Assert.AreEqual(changesCount, changesReceived);
Hope this helps.

using winforms to insert data in sql database , drawback of opening connection frequently

I am developing a front-end sales application.
Is this an efficient way of inserting data multiple times into a sql table, from a single button:
private void button1_Click(object sender, EventArgs e)
{
c.Open();
string w = "insert into checkmultiuser(username) values (#username)";
SqlCommand cmd = new SqlCommand(w, c);
cmd.Parameters.Add("#username", SqlDbType.VarChar);
cmd.Parameters["#username"].Value = textBox1.Text;
//cmd.ExecuteNonQuery();
cmd.ExecuteReader();
c.Close();
}
What are its drawbacks? One would be that again and again the connection is opened and closed when the button is clicked which would effect the speed greatly.
You ar edoing the right way: see this question: to close connection to database after i use or not? too.
Perhaps don't do the database insert for each entry, but store each entry in a DataSet, then insert them all at once, a la a save button.
For each entry do this:
String s = textBox1.Text;
If ( *\Enter validation logic*\ )
{
//Insert data into DataSet
}
else
{
//Throw error for user.
}
Then once you're ready to commit to DB, insert each item from the DataSet, similar to the examples in the other answers here.
I would open the connection once when the form opens and re-use that connection until the form is closed.
As for inserting records, the code you have is right.
From a resource management point of view it would be better if you can work out how many times you need to insert the data and then perform the operation in the one button click, perhaps iterating through a loop until the correct amount of insert operations has been completed. This means you are not constantly opening and closing the connection with each button press but instead opening it, performing the insert queries and closing the connection.
Also I recommend that you implement your code with the "using" statement, this way it will automatically handle the disposal and release of resources.
private void button1_Click(object sender, EventArgs e, string[] value)
{
try
{
using(SQLConnection c = new SQLConnection(connectionString))
using(SQLCommand cmd = new SQLCommand(c))
{
c.Open();
string w = "insert into checkmultiuser(username) values (#username)";
cmd.CommandText = w;
cmd.Parameters.Add("#username", SqlDbType.VarChar);
for(int i = 0; i < value.Length; i++)
{
cmd.Parameters["#username"].Value = value[i];
cmd.ExecuteReader();
}
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
If you can create the SQLConnection in the method then it will also allow you create it in a using statement, again taking care of managing and releasing resources.
In terms of the statement you are using I can't see any problems with it, you're using parameterized queries which is a good step to take when interacting with SQL databases.
References:
try-catch - MSDN
I don't think you should have to worry about the time lag due to opening and closing a connection, particularly if it is happening on a manually triggered button click event. Human perceivable response time is about 200 milliseconds. At best, I'd guess someone could click that button once every 100 milliseconds or so. Plenty of time to open and close a connection.
If, however, you are dealing with a routine that will be connecting to your database, you could pass in the connection, include a using statement as Mr. Keeling mentioned already, and just verify that it is ready.
Here is yet another approach, which returns a DataTable (since your original post displayed executing a Data Reader):
public static DataTable UpdateRoutine(SQLConnection c, string value) {
const string w = "insert into checkmultiuser(username) values (#username)";
DataTable table = new DataTable();
using(SQLCommand cmd = new SQLCommand(w, c)) {
cmd.Parameters.Add("#username", SqlDbType.VarChar);
cmd.Parameters["#username"].Value = value;
try {
if ((cmd.Connection.State & ConnectionState.Open) != ConnectionState.Open) {
cmd.Connection.Open();
}
using (SqlDataReader r = cmd.ExecuteReader()) {
table.Load(r);
}
}
return table;
} catch(SqlException err) { // I try to avoid catching a general exception.
MessageBox.Show(err.Message, "SQL Error");
}
return null;
}

Categories

Resources