简体   繁体   中英

C# How do I read data from an SQL Server database as soon as it is inserted?

I have a C# program that works with an SQL Server database. The setup is supposed to work over a LAN.

Now, if I insert a value into the server using a program from Computer A, how would I automatically read that data from the program in Computer B?

Basically, if I, for example, edit a text field and saved the contents to the database, the other program should update its own text field to match that of the host's.

My idea was to periodically check the database every... 2 seconds or so via a timer. Would there be performance problems with that approach? Most of the time I only need to read 1 row at a time, and the contents of the row are simple numbers and strings, nothing too big.

Are there any other approaches to this?

Thanks in advanced.

PS Running SQL Server 2005 Express and Visual Studio 2005, if that means anything.

You could periodically check the database from computer b. Add an lastupdated datetime field to the rows and only pull across the rows that have been updated / inserted since the last time the application ran on computer b.

This is much more of a decoupled solution in my opinion

I think you could have a Table where you stored the last update time.

That way you could have a cheap pooling query (just cheching if there where new updates, and only retrieve actual data from database if it was indeed changed).

正如评论中已经建议的那样,最好的办法是在给定的SqlCommand上使用SqlDependancy来等待任何更改。

只要插入表中,就可以让计算机A向计算机B发送消息(通过套接字,远程处理等)。

If you're worried about performance, maybe you could only check if the data has been modified when you need it (to modify it, or to display it).

However, if you need to monitor changes, then I would suggest that computer A sends a message to B whenever a change is made...

In addition to all the suggestions, you could also build a basic table watcher (Note this is probably buggy, I wrote it in about 15 min, but should give you the idea). I tested inserts and deletes, obviously it could be refined to detect updates depending on how fancy you want to get. You could create custom event args etc. Also I'm just throwing System.Exceptions because its proof of concept. /end disclaimer

Table Watcher Class:

public class TableWatcher
{
    private string mDatabaseConnection;
    private string mTableName;
    private bool mInitialized = false;
    private double mWatchInterval = 10;
    private System.Timers.Timer mTableTimer;
    private int mInitialRowCount;
    private int mCurrentRowCount;
    private bool mIsWatching = false;

    public event EventHandler RowsAdded;
    public event EventHandler RowsDeleted;

    protected virtual void OnRowsAdded(EventArgs e)
    {
        if (RowsAdded != null)
            RowsAdded(this, e);
    }

    protected virtual void OnRowsDeleted(EventArgs e)
    {
        if (RowsDeleted != null)
            RowsDeleted(this, e);
    }

    public int InitialRowCount
    {
        get { return mInitialRowCount; }
    }

    public int CurrentRowCount
    {
        get { return mCurrentRowCount; }
    }

    public TableWatcher(string databaseConnection, string tableToWatch)
    {

        mDatabaseConnection = databaseConnection;
        mTableName = tableToWatch;

    }

    public void Initialize()
    {
        mInitialized = true;
        mInitialRowCount = GetCurrentRows();
        mCurrentRowCount = mInitialRowCount;
    }

    public void StartWatching(double interval)
    {
        if (mInitialized == false)
        {
            throw new Exception("Table Watcher has not been initialized. Call Initialize() first.");
        }

        if (mIsWatching == true)
        {
            throw new Exception("Table Watcher is already watching. Call Stop Watching to terminate.");
        }

        if (interval == 0)
        {
            throw new Exception("Interval is invalid. Please specify a value greater than 0.");
        }

        else
        {
            mIsWatching = true;
            mWatchInterval = interval;
            mTableTimer = new System.Timers.Timer(mWatchInterval);
            mTableTimer.Enabled = true;
            mTableTimer.Elapsed += new System.Timers.ElapsedEventHandler(mTableTimer_Elapsed);
        }
    }

    void mTableTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        mTableTimer.Enabled = false;
        int rowCount = GetCurrentRows();
        if (rowCount > CurrentRowCount)
        {
            OnRowsAdded(new EventArgs());
        }

        else if (rowCount < CurrentRowCount)
        {
            OnRowsDeleted(new EventArgs());
        }

        mCurrentRowCount = rowCount;
        mTableTimer.Enabled = true;

    }

    private int GetCurrentRows()
    {
        int currentRows = 0;
        using (SqlConnection conn = new SqlConnection(mDatabaseConnection))
        {
            conn.Open();
            string query = String.Format("Select Count(*) from {0}", mTableName);
            using (SqlCommand cmd = new SqlCommand(query, conn))
            {
                object rows = cmd.ExecuteScalar();
                if (rows != null)
                {
                    currentRows = Convert.ToInt32(rows);
                }
            }
        }

        return currentRows;
    }

    public void StopWatching()
    {
        mTableTimer.Enabled = false;
        mInitialized = false;
        mIsWatching = false;
    }
}

Usage:

string dbConn = "Data Source=localhost;Initial Catalog=Test;Integrated Security=SSPI;";
            string tableName = "TestTable";
            TableWatcher t = new TableWatcher(dbConn, tableName);
            t.RowsAdded += new EventHandler(t_RowsAdded);
            t.RowsDeleted += new EventHandler(t_RowsDeleted);
            t.Initialize();
            t.StartWatching(100);

Running from a console app:

在此输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM