Click here to Skip to main content
15,882,017 members
Articles / Database Development / SQL Server

Using SQL Server Metadata and Statistics to Build a Table Explorer Application

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
1 Oct 2012CPOL8 min read 22.4K   488   7  
Develops an analogy between database table and file directory information and argues that it could be very useful if it were possible to have a similar application to Windows Explorer for database tables. Demonstrates how to obtain the information from Sql Server system tables and dynamic management
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;


/*
	Classes to make threading and interaction with a UI easier.
	
	The goal is to have a thread proc that can feed state and prgress back to the UI
	and respond to an abort request.
	There are two threading patterns supported:
	1. A long process that happens in steps. The UI reports the steps somehow.
	2. A long process without steps. All that the main program
	   requires is a note of the success or failure of the process.
*/
namespace WinFormThreading
{
    // class to pass state between interface and thread proc
    public class ThreadProcessState
    {	
		
		// process states
		// ready / working / finished / aborted
		public enum state {ready, working, done, cancelled, errored}
		state m_state = state.ready;
		
		// progress
        int  m_totalSteps = 1;     // default one step
        int  m_currentStep = 0;    // 
        object m_userData = null;  // user data
        Exception m_Exception; 
        
        public ThreadProcessState() { }
        
        public int TotalSteps { get {return m_totalSteps;} set {m_totalSteps = value;} }
        public int CurrentStep { get {return m_currentStep;} set {m_currentStep = value;} }
		public state State { get {return m_state;}}
        public bool IsDone { get {return (m_state == state.done);} }
		public bool IsCancelled { get { return (m_state == state.cancelled); } }
		public bool IsErrored { get { return (m_state == state.errored); } }
		public bool IsAborted { get { return (m_state == state.cancelled || m_state == state.errored); } }
		public bool IsWorking { get { return (m_state == state.working); } }
		public object UserData { get { return m_userData; } set { m_userData = value; } }
		public Exception Exception { get { return m_Exception; } set { m_Exception = value; } }

        // called as the thread is kicked off
        public void onStartWork()
        {
            m_currentStep = 0;
            m_state = state.ready;
        }
		// interface for setting state
        public void cancel() { m_state = state.cancelled; }  // called mainly the UI
		public void start() { m_state = state.working; }  // called by the thread class
		public void finish() { m_state = state.done; }    // called by the thread class
		public void setError(Exception ex)
		{
			m_Exception = ex;
			if (m_state != state.cancelled) // don't change state if already cancelled
				m_state = state.errored; 
		}
    }

    // declare the callback function signature
    // users of the class below pass in a function with this pattern
    delegate void ProgressStateDelegate(ThreadProcessState processState);

    /*
		wraps the nitty-gritty of a background task with feedback
	*/
	public class WorkerBase 
	{
		// the members below are passed in the constructor by the user

		// Usually a form or a winform control that implements "Invoke/BeginInvode"
		ContainerControl m_sender = null;
		// The delegate method (callback) on the sender to call
		Delegate m_senderDelegate = null;
		// the object to hold state information
		ThreadProcessState m_processState;
		
		// Constructor used by caller using ThreadPool (untested)
		public WorkerBase()	{}
		
		// Constructor called by calle using ThreadPool OR ThreadStart
		// see above for params
		public WorkerBase(ContainerControl sender, Delegate senderDelegate, ThreadProcessState state)
		{
			m_sender = sender;
			m_senderDelegate = senderDelegate;
			m_processState = state;
        }
		
		// called to start the work
		public void KickOffThread()
		{
			Thread t = new Thread(new ThreadStart(this.RunProcess));
			t.IsBackground = true;    //make them a daemon - prevent thread callback issues
			t.Start();
		}

		// Method for ThreadPool QueueWorkerItem (untested)
		public void RunProcess(object obj)
		{
			Thread.CurrentThread.IsBackground = true; //make them a daemon
			object[] objArray = (object[]) obj;
			m_sender = (System.Windows.Forms.Form) objArray[0];
			m_senderDelegate = (System.Delegate) objArray[1];
            m_processState = (ThreadProcessState)objArray[2];

			LocalRunProcess();
		}

		// Method for ThreadStart delegate
		public void RunProcess()
		{
			Thread.CurrentThread.IsBackground = true; //make them a daemon
            m_processState.onStartWork();
			LocalRunProcess();
		}
		
		/// <summary>
		/// Local Method for the actual work.
		/// </summary>
		protected virtual void LocalRunProcess()
		{
			m_processState.start();
            // do nothing implementation that just loops
            for (int step = 0; step < m_processState.TotalSteps && 
                               !m_processState.IsAborted; ++step)
			{
			    m_processState.CurrentStep = step;
				DoWorkStep(m_processState);
				// state is either working or aborted.
				// note: the completing step will not callback 
				// to avoid sending two callbacks with the done state.
				if (step < m_processState.TotalSteps-1 && 
				    m_processState.State == ThreadProcessState.state.working)
					Callback();
			}
            // send the done call back unless already aborted
			if (!m_processState.IsAborted)
			{
				m_processState.finish();
           }
			Callback();
		}
		// Overridable by the inheriting class to specialise the work done
		protected virtual void DoWorkStep(ThreadProcessState processState)
		{
			// default is a small delay - only good for testing progress lines.
			Thread.Sleep(200);
		}

		// invoked during and on completion 
		protected void Callback()
		{
			// may have to snapshot thread state to avoid > 1 done message
			m_sender.BeginInvoke(m_senderDelegate, new object[] { m_processState });
		}


	}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions