how to track changes in database - c#

I am developing a windows form application using C#. I am showing a grid with values comes from database.
My question is how to update grid when changes are made in database by means of any method.
I have tried SqlDependency class. But, my grid gets refresh continuously and i don't need it to refresh.
Is there any other way to track changes in database?
Is it possible to update data set if any one made changes in database?

Check Query Notifications that were introduced in SQL Server 2005. Query Notifications allow applications to be notified when data has changed.

Use an Open-Source class SqlDependencyEx. It is pretty easy to configure and use:
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.

You can implement SQLServer notification, instead of polling which you must be doing currently, so it refreshes the grid after a particular interval of time.
using service broker and SqlCacheDependency, you can achieve it, you can go through this article to implemnt it.

Related

c# datagridview autorefresh in LAN

I am beginner in c# with a huge problem.
An application with datagridview in front (Termin plan for one work day) works on many PC's in LAN with MS Windows Server and with MySQL database.
How can I become the changes made on one workstation AUTOMATICALY on all other PC's WITHOUT any action on them (application only started).
I have a procedure for data and datagridview refresh, I must only know WHEN I must start this procedure, that means I must know WHEN any other workstation made any changes.
Thanks for any help!
A simple solution would be to use a timer and when it elapses you refresh you gridview. so on defined period of time it will be refreshed automatically. the problem can be that if you update to often there's a overload of accessing the db. to prevent this, you could make an serverapplication which handles all data
Let's say PC 1 is starting the client application.
First it connects to server application (the server stores the reference of the client e.g. in an list).
After that the user on PC1 makes changes and click on save, the software will send the changes to the server (e.g. a custom object with all needed information).
Server saves the changes to the DB
Serverapplication give a response to the specific client if it worked or not
If it worked, Send an custom object (for example named ChangesDoneEvent) to all clients that indicates that changes have been done.
All connected clients will receive that object and know now that the have to refresh their gridview.
For further information just search for C# Multi threaded Server Socket programming. For sending custom objects over network you will find many resources in the internet too, maybe this will help you Sending and receiving custom objects using Tcpclient class in C#
Declare Delegate on your form
public delegate void autocheck();
private System.Timers.Timer TTTimer = new System.Timers.Timer();
public void autofilldgv()
{
if (this.InvokeRequired)
{
this.Invoke(new autocheck(UpdateControls));
}
else
{
UpdateControls();
}
}
private void UpdateControls()
{
//call your method here
filldgv();
}
void TTTimer_Elapsed(object sender System.Timers.ElapsedEventArgs e)
{
mymethod();
}
public void mymethod()
{
//this method is executed by the background worker
autofilldgv();
}
private void frm_receptionView_Load(object sender, EventArgs e)
{
this.TTTimer.Interval = 1000; //1 sec interval
this.TTTimer.Elapsed += new System.Timers.ElapsedEventHandler(TTTimer_Elapsed);
this.TTTimer.Start();
}
The solution provided above is actually a good way to handle this scenario. Before implementing you might also want to think about the potential fall backs. It is possible that Client PC 's IP could change and since you are using sockets. The object reference added in the list could be faulted state. You might want to think of handling this pitfall.

SQLDependency + Service Broker

I'm using SqlDependency to get notification when data in some table are changed.
private void subscribeBroker()
{
using (var conn = new SqlConnection(connString))
{
conn.Open();
var cmd = new SqlCommand("SELECT text FROM dbo.Test");
cmd.Connection = conn;
var dependency = new SqlDependency(cmd);
dependency.OnChange += dependency_OnChange;
SqlDependency.Start(connString);
cmd.ExecuteNonQuery();
}
}
void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
//Do something...
subscribeBroker();
}
It is working but I have some questions.
1) I didn't find a way how to get information which row was changed. I need to read all data from entire table to see what is different. Is there a way how to get this information? (primary ID, or something) Maybe to use different approach than SqlDependency?
2) What if "somebody" changing data very fast. It is possible that some changes will not being notified? (I'm concerned about time between notification and time when I subscribe it again.
Thank you.
About 1- query notification informs you about the fact, that something is changed. If you want to get what was changed since last time- you could probably use timestamp column.
About 2- query notification informs you about changes and then is dropped. then you again subscribe for notification again. that mean- time between dropping and creation of notifications is that time in which notification about changes is not send.
Query notifications is more for the situations, when your data is not changing frequently. For example- some cashed classification values. So- you subscribe for changes in some table, wait for changes and at the time they happen you get latest version of data. Should consider that query notification also uses server resources, so if you have huge table and want to get changes on some small subset of data, a lot of queries can be affected in terms of performance (something like indexed view).
If you need to take some action based on changed data and each change is important, then i would guess that trigger + service broker could be more effective. Or, depending on your needs, Change Data Capture.

Event Logs: SQL or not to SQL

I am building a web application that will pull event logs from multiple servers and display them into a page that I have set up. I have set it to go back 20 events for both the Application log and the System log. However, I am trying to decide if I want to save the data to a SQL database and display it from there or directly from the server into a list box. I was leaning towards directly to the list box just because the data changes so frequently. Does anyone have any suggestions or benefits from doing this any other way?
Just in case anyone is curious, here is the code I am using:
string LogType = "Application";
string serverIP = "192.168.1.5";
EventLog eventLog = new EventLog(LogType, serverIP);
int LastLog = eventLog.Entries.Count;
int i;
for (i = eventLog.Entries.Count - 1; i >= LastLog - 20; i--) {
EventLogEntry CurrentEntry = eventLog.Entries[i];
}
I actually don't see any benefits to save the logs to the database. If you're planning to serve a lot of requests from your application, you should consider caching them in your server (and I would try to do it in memory, and not in DB), and refreshing this cache from time to time. Even if your server handles few requests - it could be useful to cache the events, just for not hitting the target servers too much.
Since this data (events) seem to me a volatile in nature, and can be easily regenerated (by querying the target machines) at any time, and changes frequently - there is no need to persist it.

DataGridView live display of datatable using virtual mode

I have a DataGridView that will display records (log entries) from a database. The amount of records that can exist at a time is very large. I would like to use the virtual mode feature of the DataGridView to display a page of data, and to minimize the amount of data that has to be transferred across a network at a given time.
Polling for data is out of the question. There will be several clients running at a time, all of which are on the same network and viewing the records. If they all poll for data, the network will run very slowly.
The data is read-only to the user; they won't be able to edit any of it, just view it. I need to know when updates occur in the database, and I need to update the screen with those updates accordingly using virtual mode. If a page of data a user is viewing contains data that has change, he/she will see those updates on that page. If updates were made to data in the database, but not in the data the user is viewing, then not much really changes on the user screen (Maybe just the scroll bar if records were added or removed).
My current approach is using SQL server change tracking with the sync framework. Each client has a local SQL Server CE instance and database file that is kept in sync with the main database server. I use the information from the synchronization event to see if any changes were made to the main database and were sync'ed to the client. I need to use the DataGridView virtual mode here because I can't have thousands of records loaded into the DataGridView at once, otherwise memory usage goes through the roof.
The main challenge right now is knowing how to use virtual mode to provide a seamless experience to the user by allowing them to scroll up and down through the records, and also have records update on the fly without interfering with the user inappropriately. Has anybody dealt with this issue before, and if so, where I can see how they did it? I've gone through some of the MSDN documentation and examples on virtual mode. So far, I haven't found documentation and/or examples on their site that explains how to do what I am trying to accomplish.
Add following to form startup
dataGridView1.CellValueNeeded +=new DataGridViewCellValueEventHandler( dataGridView1_CellValueNeeded );
dataGridView1.VirtualMode = true;
Use the following code where u receive the update
dataGridView1.RowCount = (int)rowscount.TotalCount;
Add following function :
private void dataGridView1_CellValueNeeded( object sender, DataGridViewCellValueEventArgs e )
{
_cache.LoadPage( e.RowIndex );
int rowIndex = e.RowIndex % PageSize;
e.Value = datatable.rows[rowIndex][e.ColumnIndex];
}

SQL Server Notifications - My OnChange does not fire

I would like to make use of SQL Server notifications to capture insert events at my database within a winforms app. I am attempting to use the SQLDependency object. The MSDN articles make this seem pretty straight forward. So I have created a little example application to give it a try. The event only seems to fire as I enter my application the first time(MessageBox appears). Inserting data into the table does not raise the OnChange event it would seem. Can someone tell me what I'm missing? Thanks!
public Main()
{
InitializeComponent();
var check = EnoughPermission();
SqlDependency.Stop(constr);
SqlDependency.Start(constr);
if(connection == null)
{
connection = new SqlConnection(constr);
}
if(command == null)
{
command = new SqlCommand("Select ID, ChatMessage FROM dbo.Chat",connection);
}
connection.Open();
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
command.ExecuteReader();
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
MessageBox.Show("Change!");
}
While I was working in the implementation of query notification, I got the exact problem. I checked all configurations, code pieces, and even TCP settings, but nothing helped. Then, I figured out the following query to run on database and it solved my problem. Maybe you can try it.
ALTER AUTHORIZATION ON DATABASE::[Your DB] TO sa;
Your first notification is the only notification you'll get. Query Notifications are not a subscription for changes, once a notification is fired it is also invalidate. You are supposed to re-submit a new notification subscription.
If your query is notified immedeatly it means you did not get a notification for a change, but one for an invalid query. Check the values of the SqlNotificationEventArgs argument you receive. Check the Info to be Insert/Update/Delete, check the Source to be Data, check the Type to be Change.
Have a look at the Watcher Application example to better understand how you are supposed to re-subscribe when notified. For a better understanding of how the Query Notifications work, see The Mysterious Notification.

Categories

Resources