October 2007 - Posts

A Better Pager for the ASP.NET 2.0 GridView

The default pager on the ASP.NET 2.0 GridView is not pretty, and is barely practical. I've tried styling it and mucking around with the RowDataBound and RowCreated events behind the scenes, and finally I thought I'd just have to learn to live with its limitations.

This week I discovered some great pager code on CodeProject by Daniel Vaughan, and below I've shown the difference that the "Amazon-esque Pager" control made for me:

Daniel even took the time to answer my questions on getting his C# code working with databound gridviews. Brilliant!

If you're frustrated by the limits of the in-built Pager, give Daniel's code a try and improve the situation for your users at the same time.

Tags: pager, asp.net, gridview, amazon, codeproject

Book Review: Getting Real by 37signals

Over several weeks I've been reading 37signals' (makers of web apps Basecamp and Highrise) book Getting Real. The whole book can be read online at http://gettingreal.37signals.com/toc.php.

The book describes 37signals' design and operating philosophy, based on their experience working in small teams to design software. The book is easy to read: there's no code, each chapter is divided into bite-size essays, the book is well-written and a lot of the advice really makes sense, especially if you have read anything about "agile" processes previously.

37signals has well-deserved credibility, as their apps are fairly successful and can be used as prime examples of "web 2.0" (whatever your definition of that is).

Some of the book's advice perhaps directed at managing teams and influencing processes assumes that you have some level of control over your environment. For me, that isn't always the case, however, if I was in a small startup or consulting I might be able to apply more of the book's practices. Having said that, there is still plenty of practical advice that obviously comes from experience here.

Getting Real is worth a read or at least a skim, and won't cost you anything if you don't mind reading from a computer screen. As a bonus, you can download a PDF ($) version or buy a printed version too.

Tags: getting real, 37signals, book, review

Reporting Audit Changes to SQL Server 2005 objects

Following on from my last post on "Auditing Schema Changes to SQL Server 2005 objects", here's a simple bit of code that will take the EVENTDATA XML and transform it back into rows (note you need to have already run Richard's trigger and table creation script):

--EventData XML is element-centric. Below is an example, as elements will vary
--depending on what the "event" actually is:
/*
<EVENT_INSTANCE>
  <EventType>ALTER_TABLE</EventType>
  <PostTime>2007-10-02T15:39:42.707</PostTime>
  <SPID>71</SPID>
  <ServerName>SERVER</ServerName>
  <LoginName>DOMAIN\USERNAME</LoginName>
  <UserName>dbo</UserName>
  <DatabaseName>TestDatabase</DatabaseName>
  <SchemaName>dbo</SchemaName>
  <ObjectName>tblTest</ObjectName>
  <ObjectType>TABLE</ObjectType>
  <TSQLCommand>
    <SetOptions ANSI_NULLS="ON" ANSI_NULL_DEFAULT="ON" ANSI_PADDING="ON"
     QUOTED_IDENTIFIER="ON" ENCRYPTED="FALSE" />
      <CommandText>
        ALTER TABLE dbo.tblTest DROP CONSTRAINT DF_tblTest_Test
      </CommandText>
  </TSQLCommand>
</EVENT_INSTANCE>
*/
--just get back the necessary elements from the audit table - could also include
--SPID, server name, grantor, permissions, grantee, etc. depending on "event"
SELECT  --most of the elements are cast as SYSNAME...difficult to find the *real* datatypes
        O.[EventData].value('(/EVENT_INSTANCE/EventType) [1]', 'SYSNAME') AS [EventType],
        O.[EventData].value('(/EVENT_INSTANCE/PostTime) [1]', 'DATETIME') AS [PostTime],
        O.[EventData].value('(/EVENT_INSTANCE/LoginName) [1]', 'SYSNAME') AS [LoginName],
        O.[EventData].value('(/EVENT_INSTANCE/ObjectType) [1]', 'SYSNAME') AS [ObjectType],
        --put together full object name from database, schema and object
        O.[EventData].value('(/EVENT_INSTANCE/DatabaseName) [1]', 'SYSNAME') + '.' +
            O.[EventData].value('(/EVENT_INSTANCE/SchemaName) [1]', 'SYSNAME') + '.' +
            O.[EventData].value('(/EVENT_INSTANCE/ObjectName) [1]', 'SYSNAME') AS [FullObjectName],
        --actual command text (may be very long)
        O.[EventData].value('(/EVENT_INSTANCE/TSQLCommand/CommandText) [1]', 'NVARCHAR(MAX)') AS [CommandText]
FROM    --using Richard's example, get data from the "Audit.Objects" table, with XML column
        Audit.Objects O WITH (NOLOCK)

My standard disclaimer is "it worked on my machine". Your mileage may vary.

The output from this query is a normal rowset and can be used in whatever reporting tool you favor (e.g. for me, Reporting Services).

p.s. Thanks to Whitney for the pointer on XML data types and queries!

Tags: sql server, audit, schema

Auditing Schema Changes to SQL Server 2005 objects

I recently needed to implement a lightweight, simple audit trail in SQL Server 2005. After googling and finding many, many ways, I settled on Richard's recent blog post over at GeekDojo titled "Super easy SQL Server 2005 Database Schema change auditing".

Richard has posted a short, helpful script to audit data definition (CREATE, DROP, ALTER) SQL statements to a central table using a simple trigger and the XML data type. This means I can keep an audit trail of schema changes, along with all the information available (user name, date & time, SQL statement, etc.)

I'm looking forward to working with this. Any advice for pulling data out of the XML data type?

Tags: sql server, audit, schema