Tracing SQL Statements generated by Entity Framework

January 28, 2010

The DataContext of Linq2Sql provides a Log property that one can assign a TextWriter to retrieve the text of the SQL statements generated by Linq. The ObjectContext of Entity Framework does not contain such an easy way to trace generated SQL statements.

An MSDN blog provides a solution in the form of an Entity Framework provider which simply wraps the existing EF data provider.

Integration into an existing project is pretty simple and straight forward (see detailed discussion on MSDN):

  • Register Provider Factories in web.config or app.config
  • Derive a class (ExtendedEntities) from the generated Entities class
  • Use the ExtendedEntities class throughout the code

To be able to switch between logging and non-logging code, I found it helpful to modify this approach a bit.

First, all “extended” functionality is activated in the code using a #define symbol. If the symbol is defined, there will also be a compiler warning to notify the developer whether the build is for debug or production.

Second, the tracing functionality will only be activated if the config file contains an AppSetting named “EFTraceDir”.

Next, I replaced the entity context creation code from

using (var context = new Entities())

to a factory pattern

using (var context = Entities.Create())

with the method

static Entities Create()
{
#if trace
  if (TraceEnabled)
  {
    ExtendedEntities context = new ExtendedEntities();
    context.CommandFinished += EFCommandFinished;
    return context;
  }
#endif
  return new Entities();
}

CommandFinished is an event defined by the EFTracingProvider, and will be use to log the generated SQL to files.

Statements generated by Linq do not have a name, so it would be hard to associate any generated SQL statement with the original Linq definition.

Thus we need to find out where in the code the statement was invoked.

A quick search on StackOverflow resulted in the .Net classes StackTrace and StackFrame. This little routine list the whole stack and returns the class name causing the invocation, which corresponds to the aspx page name (in case you want to trace an ASP.Net application):

private static StringBuilder ListStack(out string sType)
{
  StringBuilder sb = new StringBuilder();
  sType = "";

  StackTrace st = new StackTrace(true);
  foreach (StackFrame f in st.GetFrames())
  {
    MethodBase m = f.GetMethod();
    if (f.GetFileName() != null)
    {
      sb.AppendLine(string.Format("{0}:{1} {2}.{3}",
        f.GetFileName(), f.GetFileLineNumber(),
        m.DeclaringType.FullName, m.Name));

      if (!string.IsNullOrEmpty(m.DeclaringType.Name))
        sType = m.DeclaringType.Name;
    }
  }

  return sb;
}

Omitting the condition (f.GetFileName() != null) will also list the .Net system assemblies and methods.

Putting it all together, we simply write the command, its parameters, and the stack trace into a file. The file is named after the aspx page name (i.e. the bottom-most type name on the stack), the statement length, and the statement ID.

private static void EFCommandFinished(object sender, CommandExecutionEventArgs e)
{
  string sType;
  StringBuilder sb = ListStack(out sType);

  System.IO.File.WriteAllText(
    Path.Combine(EFTraceDir, string.Format("{2} {0:D9} {1:D9}.txt",
      e.Command.CommandText.Length, e.CommandId, sType)),
    string.Format("{0}\r\n{1}\r\n{2}\r\n",
      e.Duration, e.ToTraceString(), sb.ToString()));
}

Choice of the file name pattern makes it easy to sort files by originating aspx name and statement length.

Multiple files with equal length (as shown in the filename) indicate that the same statement is used several times, a good indicator to check database access code and cache results.

The generated SQL also gives you an idea of how your Linq queries are translated, and whether you need to optimize them or rewrite them to a) reduce statement length and b) reduce the amount of selected data.

private static void EFCommandFinished(object sender, CommandExecutionEventArgs e)
{
string sType;
StringBuilder sb = ListStack(out sType);

System.IO.File.WriteAllText(
Path.Combine(EFTraceDir, string.Format(“{2} {0:D9} {1:D9}.txt”, e.Command.CommandText.Length, e.CommandId, sType)),
string.Format(“{0}\r\n{1}\r\n{2}\r\n”, e.Duration, e.ToTraceString(), sb.ToString()));
}


Disabling Submitting Control in ASP.Net

January 27, 2010

If you want to disable the control triggering form submission in ASP.Net, two modes need to be distinguished.

If you use AjaxControlToolkit and the control is placed inside an UpdatePanel, you need to hook into the ScriptManager’s BeginRequest and EndRequest events, as shown in this blog post.

If the form uses the standard HTML Post functionality, you may think about disabling the triggering control in the onsubmit event of the form. However, a disabled button cannot submit a form in ASP.Net, even if it is disabled only in the onsubmit event handler.

I found this article describing the problem and the solution is to have a <div> which is initially invisible, and will be displayed in front of the form on submitting by setting its z-index and opacity.

In my solution, however, I chose not to set a fixed opacity for the hiding div (and thus instantaneously dimming the input form), but rather slowly increase the opacity in a timer.

Based on the original article, here is my solution:

<style type="text/css" >
.FreezePaneOff
{
      visibility: hidden;
      display: none;
      position: absolute;
      top: -100px;
      left: -100px;
}

.FreezePaneOn
{
      position: absolute;
      top: 0px;
      left: 0px;
      visibility: visible;
      display: block;
      width: 100%;
      height: 100%;
      background-color: #666;
      z-index: 999;
      filter:alpha(opacity=0);
      opacity:0.0;
      padding-top: 20%;

      font-size: 48px;
      font-weight: bold;
      text-align: center;
}
</style>

<script type="text/javascript">
    var oldSubmit = theForm.onsubmit;
    var opac = 0.0;

    function NewSubmit() {
        var o = true;
        if (oldSubmit) {
            o = oldSubmit();
        }
        if (o) {
            document.getElementById('freeze').className = "FreezePaneOn";
            setTimeout("fadeout()", 100);
        }
        return o;
    }

    function fadeout() {
        opac += 1.0;
        if (opac >= 70)
            return;

        var f = document.getElementById('freeze');
        f.style.opacity = opac / 100.0;
        f.style.filter = "alpha(opacity=" + opac + ")";

        setTimeout("fadeout()", 100);
    }

    theForm.onsubmit = NewSubmit;
</script>

Stripping Accents from Strings in C#

January 26, 2010

Unicode defines a concept called normalization (Unicode, Wikipedia) to define the equivalence of composed and decomposed representations of characters.

In .Net, the string.Normalize() method can be used to convert strings between normalization forms. If a string is in normalization form NormalizationForm.FormKD (full compatibility decomposition), the combing and modified marks are stored as separate characters, and their Unicode category can be retrieved calling the GetUnicodeCategory() method.

Thus, stripping the characters of a string from their accents, one has to perform the following steps:

  • Normalize the string into full compatibility decomposition
  • Remove the characters belonging to a “Mark” category
  • Return the result

Here is the C# code implementing this function:

using System.Text;
using System.Globalization;

public string StripAccents(string s)
{
  StringBuilder sb = new StringBuilder();
  foreach (char c in s.Normalize(NormalizationForm.FormKD))
    switch (CharUnicodeInfo.GetUnicodeCategory(c))
    {
      case UnicodeCategory.NonSpacingMark:
      case UnicodeCategory.SpacingCombiningMark:
      case UnicodeCategory.EnclosingMark:
        break;

      default:
        sb.Append(c);
        break;
    }
  return sb.ToString();
}

Listing ON DELETE CASCADE Constraints in MS SQL Server 2000

January 23, 2010

I needed to run my checks on ON DELETE CASCADE Constraints in MS SQL Server on SQL Server 2000, and needed to adjust the system table names and columns accordingly.

These are the queries adjusted for SQL Server 2000:

DECLARE @t NVARCHAR(128)
SET @t = 'MyTable'

SELECT p.name,
    objectproperty(fk.constid, 'CnstIsDeleteCascade') OnDelete,
    t.name
FROM dbo.sysforeignkeys fk
INNER JOIN dbo.sysobjects t ON fk.fkeyid = t.id
INNER JOIN dbo.sysobjects p ON fk.rkeyid = p.id
WHERE p.name = @t
ORDER BY 1, 3

SELECT DISTINCT p.name,
    objectproperty(fk.constid, 'CnstIsDeleteCascade') OnDelete,
    t.name,
    objectproperty(fk2.constid, 'CnstIsDeleteCascade') OnDelete,
    tt.name
FROM sysforeignkeys fk
INNER JOIN sysobjects t ON fk.fkeyid = t.id
INNER JOIN sysobjects p ON fk.rkeyid = p.id
INNER JOIN sysforeignkeys fk2 ON fk2.rkeyid = t.id
INNER JOIN sysobjects tt ON fk2.fkeyid = tt.id
WHERE p.name = @t
AND t.id <> p.id
ORDER BY 1, 3, 5

Deferred Object Instantiation in C#

January 21, 2010

If a class declaration contains object members, the members are typically assigned and instantiated in a constructor or in the class definition:

public class Foo
{
  private Bar bar = new Bar();
  private Baz baz;

  public Foo(int ID)
  {
    baz = new Baz(ID);
  }
}

If the instantiation of member objects is costly, e.g. when fetching records from a database, deferred instantiation might be preferred, especially if it is not certain that the object actually needs to be instantiated.

This led me to the creation of a generic DeferredObject class, the constructor of which is passed a function or delegate to fetch the data in case it is needed:

public class DeferredObject<T>
{
  public delegate TT DeferredObjectFetcher<TT>();

  public DeferredObject(DeferredObjectFetcher<T> Fetcher)
  {
    this.Fetcher = Fetcher;
  }

  private DeferredObjectFetcher<T> Fetcher;
}

The fetch operation (to instantiate the object) is invoked the first time the object’s Value property is invoked:

  private bool Fetched;
  private T _Value;

  public T Value
  {
    get
    {
      if (!Fetched)
      {
        _Value = Fetcher();
        Fetched = true;
      }
      return _Value;
    }
  }

An implicit type conversion operator can be useful, e.g. to compare an int to a DeferredObject without explicitly using the .Value method. The ToString() method redirects to the ToString() of the Value:

  public static implicit operator T(DeferredObject<T> co)
  {
    return co.Value;
  }
  public override string ToString()
  {
    return Value.ToString();
  }

Finally, allow the DeferredObject to be reset and re-instantiated on demand:

  public void Clear()
  {
    Fetched = false;
    _Value = default(T);
  }

Rewriting the original sample code to use the DeferredObject solution:

public class Foo
{
  private Bar bar = new DeferredObject<Bar>(delegate() { return new Bar(); });
  private Baz baz;

  public Foo(int ID)
  {
    baz = new DeferredObject<Baz>(delegate() { return new Baz(ID); });
  }
}

DeferredObjects may of course depend on other DeferredObjects:

  baz = new DeferredObject<Baz>(delegate() { return new Baz(ID); });
  bar = new DeferredObject<Bar>(delegate() { return new Bar(Baz.Value.BarID); });

wpxslgui – WordPress XML Export Converter

January 18, 2010

wpxslgui is a Windows application which converts an XML File generated by the WordPress Export function into an HTML or Word HTML document.

This new program is based the two XSL style sheets I created earlier to process WordPress XML Exports: the “Single HTML” XSL and the “Table of Contents” XSL.

The program’s features are:

  • Convert WordPress XML to HTML Table of Contents with links to the original blog
  • Convert WordPress XML to a single HTML file allowing filter by category (JavaScript)
  • Convert WordPress XML to Word HTML document (can be saved as .doc or .docx in Word)

Simply download wpxslgui, export your WordPress blog to XML, and convert into any of the supported output formats.

Let me know what you think about it ;)


More Documentation Generators for dbscript

January 14, 2010

The number of documentation generators included in dbscript is growing steadily.

Version 1.00 already implemented

and fixed the

All links show documentation on the MS AdventureWorks (2005) database.

Version 1.01 further includes

The XSLT style sheets shipping with dbscript need a bit of revising too, for example, to include separate sections for table indexes and constraints which are currently not output.


SMOscript 0.16

January 14, 2010

Version 0.16 of SMOscript includes an option to script just a single object.

Using the option -o [schema.]name, one can reduce the output of SMOscript to an object matching the name, or schema.name combination. All child objects (triggers, constraints) will be included.

This feature has been requested recently.

The complete set of parameters of SMOscript looks like this:

smoscript 0.16.3665.39354 (c) by devio.at 2008-2010

    list and script databases and database objects.

    usage: smoscript [options] [command]

    options: (leading '-' or '/')

    -s server       server name
    -d database     database name
    -o [schema.]object  object name
    -u username     username (default: integrated authentication)
    -p password     password (if -u is missing, password for sa)

    -r              generate DROP statements
    -i              include IF NOT EXISTS statements

    -f filename     output to file
    -F directory    output to directory

    -A              current ANSI codepage
    -O              ASCII
    -T              Unicode
    -U              UTF8

    commands:

    l       list databases on server (implied by -s)
            list objects in database (implied by -s -d)
    s       script all objects (implied by -s -d -F/-f)
            script single object (implied by -s -d -o)
    db      list database properties

The lastest version of SMOscript is available for download here.


Year End / New Year

January 10, 2010

Dear Reader,

you generated an average of 200 visits per day (whatever it is that WordPress counts) this year (if you accept the common definition of a year ;) ), reaching a total of 100.000 visits recently.

Your (and my) most favorite posts dealt with C#, Visual Studio, and SQL Server.

Of course I tried to keep everybody updated on my products dbscript, automssqlbackup, smoscript and oraddlscript that generated an impressive number of downloads.

You can browse through the list of all my blog entries (2007-200) and filter by category on this page which has been generated by one of my WordPress XSLTs.

Thank you for visiting, leave comments, and… a happy new year!


Follow

Get every new post delivered to your Inbox.