SQL Server : Connect By Prior

December 21, 2005

Oracle database give us the posibility to retrive hicherical data from database using Connect By Prior. This sentence is usefull for retrive Trees from tables sorted by level, but SqlServer lacks of this sentence turns Trees retriving topics a little messy. But consider this example that could help make things easier.


First consider this table:


CREATE TABLE Topic (
 TopicId  VARCHAR(255) ,
 DisplayName  VARCHAR(255) NULL ,
 ParentTopicId VARCHAR(255) NULL ,

 CONSTRAINT UK_TopicId UNIQUE CLUSTERED (
  TopicId )
)
GO


In Topic table  TopicId defines the topic uniqueidentifier and the ParentTopicId defines who is it’s parent.


Now consider this StoredProcedure


CREATE PROCEDURE dbo.TopicGetTree
 @TopicId VARCHAR(255) = NULL
AS
BEGIN
 SET NOCOUNT ON


 DECLARE @Level INT
 DECLARE @ParentTopicId VARCHAR(255)


 CREATE TABLE #output (
  ParentTopicId VARCHAR(255),
  TopicId VARCHAR(255),
  Level INT
 )


 CREATE TABLE #stack (
  Parent VARCHAR(255),
  Item VARCHAR(255),
  Level  INT
 )


 INSERT INTO #stack VALUES (NULL, @TopicId, 1)


 SELECT @Level = 1


 WHILE @Level > 0
 BEGIN
  IF EXISTS (SELECT 1 FROM #stack WHERE [Level] = @Level)
  BEGIN


   SELECT
    @ParentTopicId = Parent,
    @TopicId = Item
   FROM
    #stack
   WHERE
    Level = @level


   INSERT INTO #output VALUES (@ParentTopicId, @TopicId, @Level)


   DELETE FROM #stack WHERE Level = @Level AND Item = @TopicId


   INSERT INTO #stack (Parent, Item, Level)
   SELECT
    ParentTopicId,
    TopicId,
    @Level + 1
   FROM Topic
   WHERE Topic.ParentTopicId = @TopicId


   IF @@ROWCOUNT > 0
    SELECT @Level = @Level + 1
   
  END
  ELSE
  BEGIN
   SELECT
@Level = @Level - 1
  END
 END


 SELECT
              ParentTopicId,
              TopicId,
              Level
 FROM   
               
#output
END
GO

A useful feature that ASP.NET lacks is the ability to assing the input focus to a particular control when page is displayed. In ASP.NET 2.0, the Page class is a purposely endowed with the Page.SetFocus method. The following code shows hot to set the focus to a TextBox control named EmailTextBox.


protected void Page_Load(object sender, EventArgs e)
{
   if(this.IsPostBack)
   {
      this.SetFocus(EmailTextBox.ClientId);
   }

)


The SetFocus method caches the ID of the Control and forces the Page class to generate ad hoc script code when the page is rendered. The following code shows an alternative approach to setting the input focus.

<form runat=”server” defaultFocus=”EmailTextBox” >
.
.
.
</
form>


You can set the DefaultFocus property on a form to denote which control should receive the focus. This is equivalent to calling SetFocus. The difference is that if one control at a time requests the focus through SetFocus, the fefault focus is ignored.


 

The great news about the scripting object model in ASP.NET 2.0 is that allows you to call a sever side function without redrawing whole page. Previously for the same functionallity we used some third party frameworks like AJAX.NET or implemented our own framework based on XMLHTTP Activex Object or  XMLHTTP Native Mozilla Object. Now this is a built-in functionallity. We can use these callbacks to: Refresh only a panel on page or retrive on-demand data from server. Let’s take a look to see how it works.


A script callback begins with a client-side event that triggers WebForm_DoCallback function (ASP.NET JS Native Function). These function requiers some arguments:



WebForm_DoCallback( 
   pageID,  //ID of the page that makes the call
   argument, //string argument to pass server-side code
   returnCallback, //JavaScript function that is invoked after callback occurs
   context, // value the caller needs to pass to return callback
   errorCallback //Javascript function that is invoked when server side call fails
)


Every control that wants to support out-of-band callback must implement the ICallbackEventHandler interface:



interface ICallbackEventHandler
{
 
    string RaiseCallbackEvent (string eventArgument);

)


The RaiseCallbackEvent should retrive server-side values based on the parameter(s) and pack everything into a return string.


Client-Side Postback Cycle


The page posts backs to the server and gets initilized as usual. The Init and Load events are fired, and the IsCallback property is set to true. RaiseCallbackEvent is invoked when loading phase is completed. After that, the request ends withouth entering the rendering phase. A client-side system component (the Callback Manager) is a script library sent to the client by ASP.NET, it’s responsible for creating a request to the server, and will fire the appropiate server-side event. It also parses the response and passes the appropiate data to the specified JavaScript return Callback.


Some notes


Theoe interface could be implemented by any System.Web.Control hicherarcy control.


Should we write the to WebForm_DoCallback your self? Should you about its details? Not neccesarily. The GetCallbackEventReference method on the Page.ClientScript  object on Page class returns the script string that starts the callback. You prefix this string with Javascript: and attach it to any action event attribute on control. (ex. htmlButton.Attributes["onclick"]).


GetCallbackEventReference example



protected void Page_Load(object sender, EventArgs e)
{
   htmlButton.Attributes["onclick"] = Page.ClientScript.GetCallbackEventReference(this, “argument”, “callback”, “preCallbackFunction”);
)


//About the arguments of GetCallbackEventReference
control: control that handles the client callback.
argument: argument which is passed to the server-side function
callback: javascript function that is triggered from a successfull client side callback.
preCallbackFunction: javascript function that is evaluated on client prior server side callback.