blog.mha.dk
The on-line blog of Michael Holm Andersen

InvalidCastException on linq DB submit with non-integer key – aka LinqToSQL bug

Friday, 27 November 2009 09:02 by mha

Wasted a whole day on a (confirmed) bug in LinqToSQL. The problem is this:

“When database contains two tables, both with automatic integer primary keys, and a relationship between a unique char field in one and a non-unique char field in the other, inserting new rows into the second table fails on submit with InvalidCastException"

The error returned be LinqToSQL is: specified cast is not valid

I have a table which contains a char column which is ForeignKey to a unique char column in another table. In my case the column is “CurrencyISO” (e.g. the value DKK) in one table which has a FK relation to a unique ISO4217_ISO column in my Currency table.

Running on my development machine (Windows 7, x64) the code executes without problem – however running on my development server (Windows Server 2008 Web edition, x64) LinqToSQL at random (more or less!) throws the exception: specified cast is not valid

After having spend hours on the bug (I thought it was related to different OS and/or differences in MS SQL Server or something other “weird”), I found this article on Microsoft Connect which confirms the bug and the message “I can confirm that this bug has been fixed for .NET 4.0, which is why it's still failing with .NET 3.5 SP”

However a hotfix is available (and it will fix this bug!) – You can download yourself from Connect or if you’re running an x64 OS (Vista and/or Windows Server 2008), you can simple download the below .ZIP file which contains the hotfix (I’ve installed this on my Windows Server 2008 Web edition (x64), rebooted (an IIS reset should be enough!) and finally the bug was gone!!

Grab the hotfix (NDP35SP1-KB963657-x64.exe) for x64 platforms here:

Categories:   LINQ | SQL/Database
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

Setting DataContext Connection String at runtime

Tuesday, 17 November 2009 14:04 by mha

I’m working on a portal/e-shop solution where I’ll be using multiple databases and needs to change the Connection used by my DataContext object at runtime.

I use the HttpContext.Current.Items collection to store which connection is currently “active” - this is setup in the Application_AcquireRequestState event in Global.asax which fires for every request – and using the OnCreated method that is called as part of the DataContext’s constructors, I can easily change which connection to use at runtime.

The good thing about putting the “connection switch” in the OnCreated method is that no matter how I use the DataContext this code is always executed (I have a LinqUtil class which implement a request-scoped DataContext pattern for LINQ to SQL), and using the below approach I don’t have to worry about which Connection is used as this is transparent to any helper / DAL classes.

The code for the partial class which implements the OnCreated method for my DataContext looks (something!) like this:

   1: public partial class GWportalDataContext : System.Data.Linq.DataContext
   2:     {
   3:         // In order to use multiple database connections we use the HttpContext.Current.Items collection to store which database we're currently using (per request)
   4:         partial void OnCreated()
   5:         {
   6:             switch (HttpContext.Current.Items[ConfigurationManager.AppSettings["WebsiteHttpContextItemKey"]].ToString())
   7:             {
   8:                 case "GWDK":
   9:                     this.Connection.ConnectionString = ConfigurationManager.ConnectionStrings["GWportalConnectionDK"].ConnectionString;
  10:                     break;
  11:                 case "GWNO":
  12:                     this.Connection.ConnectionString = ConfigurationManager.ConnectionStrings["GWportalConnectionNO"].ConnectionString;
  13:                     break;
  14:                 default:
  15:                     this.Connection.ConnectionString = ConfigurationManager.ConnectionStrings["GWportalConnectionDK"].ConnectionString;
  16:                     break;
  17:             }
  18:         }
  19:     }

LINQtoSQL Samples

Monday, 9 November 2009 18:46 by mha

If you’re looking for some great LINQtoSQL samples look no further than MSDN.

As part of the 101 LINQ samples project, Microsoft has put together some nice LINQtoSQL samples – take a look at:

Categories:   SQL/Database | LINQ
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

MS SQL Server 2008 Express (x64) memory leak?

Thursday, 8 October 2009 13:58 by mha

I’ve been using MS SQL Server 2008 Express edition (x64) on Vista Ultimate SP2 quite a lot the last month and was running out of memory almost every day (the SQL Engine using +1GB of Memory!!)

Today I updated my SQL Instance to SQL Server 2008 Service Pack 1 and now it only uses between 100-150MB of memory .. So it seems that there might be a memory leak in the “prior SP1 version”

Download SQL Server 2008 Service Pack 1

Categories:   SQL/Database
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

SQL Azure Manager

Thursday, 17 September 2009 14:50 by mha

sqlazuremanager

If you’re into SQL Azure you have probably found out that SSMS is not fully compliant with SQL Azure, which means that you more-or-less have to use SQLCMD to do any real work (which kind of sucks!)

Today, however I discovered SQL Azure Manager which is a lightweight tool for managing SQL Azure databases – it’s MUCH better than using SQLCMD and can be downloaded at: http://hanssens.org/post/SQL-Azure-Manager.aspx

Categories:   SQL/Database | Tools
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

GridView and the RowCommand event

Wednesday, 26 August 2009 23:42 by mha

The GridView is a powerful control, however dealing with multiple different column types in the RowCommand event still is a little messy! – I’ve put together a small sample which utilize the most common column types.

I have a GridView which looks like this:

<asp:GridView ID="GridView1" runat="server" AllowSorting="True"
    AutoGenerateColumns="False" DataKeyNames="ItemID" DataSourceID="LinqDataSource1"
OnRowCommand="GridView1_RowCommand">
    <Columns>
        <asp:BoundField DataField="ItemID" HeaderText="ItemID" Visible="false" InsertVisible="False"
            ReadOnly="True" SortExpression="ItemID" />
        <asp:HyperLinkField DataTextField="Name" HeaderText="Produkt" DataNavigateUrlFields="ItemID"
            DataNavigateUrlFormatString="ProductView.aspx?id={0}" SortExpression="Name" />
        <asp:BoundField DataField="ItemNo" HeaderText="Varenr." SortExpression="ItemNo" />
        <asp:TemplateField HeaderText="Pris u/moms" SortExpression="DefaultPrice">
            <ItemTemplate>
                <%# CalculatePrice(Eval("DefaultPrice"), Eval("ItemID"))%>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Antal">
            <ItemTemplate>
                <asp:TextBox ID="txtQuantity" runat="server" Style="text-align: right" Width="50">1</asp:TextBox>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Discount">
            <ItemTemplate>
                <%# ShowProductDiscount(Eval("ItemID"))%>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:ImageButton ID="ImageButton1" CommandArgument='<%#Container.DataItemIndex %>'
                    CommandName="AddToBasket" runat="server" ToolTip="Klik for tilføje til kurv"
                    ImageUrl="~/Images/icon_addtobasket.gif" />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

Note: I have a couple of public methods which calculates the price and discount, these methods are omitted in the below code (to simply things!).

In the RowCommand (code-behind) I have this:

protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
   {
       if (e.CommandName == "AddToBasket")
       {
           // get the index for the row which fired event
           int index = Convert.ToInt32(e.CommandArgument);

           // get primary key value from gridview DataKeys collection
           int ItemID = Convert.ToInt32(this.GridView1.DataKeys[index].Value);

           // get the current GridViewRow
           GridViewRow row = (GridViewRow)((Control)e.CommandSource).Parent.Parent;

           // get the HyperLinkField column
           HyperLink hyper = row.Cells[1].Controls[0] as HyperLink;
           if (hyper != null)
           {
               string LinkText = hyper.Text;
           }

           // get the TextBox column (Find control, cast to TextBox and convert .Text to short)
           short Quantity = short.Parse(((TextBox)GridView1.Rows[index].FindControl("txtQuantity")).Text);

           // get Price (CalculatePrice() return a string which is converted to a DataBoundLiteralControl)
           DataBoundLiteralControl lit = row.Cells[3].Controls[0] as DataBoundLiteralControl; 
           if (lit != null)
           {
               float Price = float.Parse(lit.Text);
           }

       }
   }

There you have it! – The ‘trick’ is to get your hands on the GridViewRow and then cast the various row.Cells[N] to the proper type (like above with the HyperLinkField), this technique works just as well with buttonfield and checkboxfield columns.

If don’t want to “spend time” pulling out the GridViewRow, you can also take the slightly more ‘directly’ approach (as I’ve done above with the TextBox column), where I (instead of using ‘row’) uses the GridView1.Rows[index].FindControl syntax instead (I prefer pulling out the GridViewRow, though).

That’s it! – Have fun poking around that RowCommand event! :-)

SQL Injection Attack - once again...

Monday, 26 May 2008 17:57 by mha

As you might have read in the news, Denmark is currently the target of Injection Attacks which mostly is a problem with pourly programmed websites - if you're worried about wether your website is up to the task of rejecting these attacks .. take a look at this article which explains the problem and also shows some solutions: http://www.sitepoint.com/article/sql-injection-attacks-safe

Categories:   ASP.NET | C# | SQL/Database
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

Left Outer Join using LINQ

Saturday, 5 April 2008 18:18 by mha

Often we need to do a left/right outer join. A friend of mine asked me how to do this using LINQ - and the short answer is this:

from s in Suppliers
    join c in Customers on s.City equals c.City into temp
    from t in temp.DefaultIfEmpty()
    select new {
    SupplierName = s.CompanyName,
    CustomerName = t.CompanyName,
    City = s.City
    }

Using LINQPad, simply make a connection to the Northwind database and execute the above query.

The "CustomerName" column will contain NULL for the rows in the Suppliers table, where no Customers exists for that specific city.

 

Free SQL Server 2008 book

Wednesday, 27 February 2008 08:12 by mha

Sign up to dowload a free copy of the Introducing SQL Server 2008 book when it's published:

http://csna01.libredigital.com/?urss1q2we6

 

Automatic script backup of your databases

Monday, 22 October 2007 09:11 by mha

Continuing on the backup article I wrote yesterday, I'll show you how I do a daily script backup (.sql) of all the databases on my development machine. Before we take a look at the script, we'll need a couple of utilities (don't worry, they're free!).

Database Publishing Wizard (part of SQL Server Hosting Toolkit)
WinRAR (you probably already got this one installed!)

Now.. let's take a look at the script - it goes something like this: 

echo off
cls
echo ***************************************************************************
echo ** Script all objects in databases and save them in 'dd-mm-yyyy' folder  **
echo ***************************************************************************
cd C:\temp
C:
md %date%
cd %date%
"C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz" script -C "Data Source=.\SQLEXPRESS;Initial Catalog=PlastLogistik;Integrated Security=True" PlastLogistik.sql
"C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz" script -C "Data Source=.\SQLEXPRESS;Initial Catalog=SonofonAutomatiseretBrugerhaandtering;Integrated Security=True" SonofonAutomatiseretBrugerhaandtering.sql
"C:\Program Files\Microsoft SQL Server\90\Tools\Publishing\sqlpubwiz" script -C "Data Source=.\SQLEXPRESS;Initial Catalog=aspnethotel;Integrated Security=True" aspnethotel.sql
echo ***************************************************************************
echo ** RAR compress all .sql script files                                    **
echo ***************************************************************************
"C:\Program Files\WinRAR\WinRAR.exe" -ibck a PlastLogistik.rar PlastLogistik.sql
"C:\Program Files\WinRAR\WinRAR.exe" -ibck a SonofonAutomatiseretBrugerhaandtering.rar SonofonAutomatiseretBrugerhaandtering.sql
"C:\Program Files\WinRAR\WinRAR.exe" -ibck a aspnethotel.rar aspnethotel.sql
echo WinRAR has completed execution
echo ***************************************************************************
echo ** Delete all .sql script files                                          **
echo ***************************************************************************
del PlastLogistik.sql
del SonofonAutomatiseretBrugerhaandtering.sql
del aspnethotel.sql
echo .SQL files deleted

It's really simple, actually - Let's break it down:

1) I switch to the default backup directory, in the example "c:\temp"

2) A new directory with todays date is created (if you're using DK locals the format is dd-mm-yyyy)

3) Using the Database Publishing Wizard, I do a script backup of each database (only three in this example, add as many as needed!)

4) Using WinRAR and the switch "-ibck" to disable the GUI, a .rar file is created for each .sql file (you can also compress all .sql files to a single .rar file if you prefer!)

5) Last step is to delete all those nasty .sql files (of course a "del *.sql" could also be used to minimize script if you don't store additional .sql files in the directory!)

Categories:   SQL/Database | Tools
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed