LinqDataSource exceptions
Prerequisite: LinqDataSource & SqlDataSource Master/Details
When working with the LinqDataSource, you may get the exceptions listed below.
1. Operator '==' incompatible with operand types 'Int32' and 'Object'
The exception occurs because anytime a ControlParameter in the WhereParameters collection (IDictionary<string, object>) is null, it gets treated as type Object causing the LINQ dynamic expression parser comparison to fail. Consider the code snippet below:
<asp:LinqDataSource ID="LinqDataSource2" runat="server" ContextTypeName="DataClassesDataContext"
Select="new (OrderID, ProductID, UnitPrice, Quantity, Discount, Order)" TableName="Order_Details"
Where="OrderID == @OrderID">
<WhereParameters>
<asp:ControlParameter ControlID="GridView1" Name="OrderID" PropertyName="SelectedValue"
Type="Int32" />
</WhereParameters>
</asp:LinqDataSource>
This is part of the classic Master/Details scenario where the LinqDataSource fetches the Order Details based on the OrderID selected in the GridView1.
When the page loads the first time, the OrderID ControlParameter is equal to GridView1.SelectedValue. GridView1.SelectedValue is null since no record has been selected in the GridView1 yet. Unfortunately, the LinqDataSource still attempts to fetch the data. The Linq expression parser treats the null parameter as type Object and the comparison fails because it was expecting type Int32.
What we need here is a way to prevent the Select from occurring when any parameter is null. The LinqDataSource, unlike the SqlDataSource, for some reason, does not have a CancelSelectOnNullParameter property. This property when set to true, will cancel the select when any parameter in the SelectParameters collection is null.
We can implement this by handling the Selecting event of the LinqDataSource and call the Cancel method when any WhereParameter is null like so:
protected void LinqDataSource2_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{
foreach (KeyValuePair<string, object> kvp in e.WhereParameters)
{
if (kvp.Value == null)
{
e.Cancel = true;
return;
}
}
}
2. Operator '==' incompatible with operand types 'Guid' and 'String'
This exception occurs in cases where a parameter in the WhereParameters collection is of type Guid.
<asp:LinqDataSource ID="LinqDataSource2" runat="server"
ContextTypeName="DataClassesDataContext"
Select="new (DummyID, FirstName, LastName)" TableName="DummyTables"
Where="DummyID == @DummyID" onselecting="LinqDataSource2_Selecting">
<WhereParameters>
<asp:ControlParameter ControlID="GridView1" Name="DummyID"
PropertyName="SelectedValue" Type="Object" />
</WhereParameters>
</asp:LinqDataSource>
In the snippet above, you can see that the GridView1.SelectedValue is defined as a WhereParameter for the LinqDataSource. DummyID is the primary key of the data in GridView1 and is of type Guid. In the ControlParameter, its Type is set to Object because Guid is not available in the TypeCode enum. Unfortunately, this results in the linq expression parser treating the value as type String causing the comparison to fail.
According to the Dynamic Expression API, a flavor of which is used by the LinqDataSource internally, we can perform explicit conversions using the syntax type(expr) where type is a type name optionally followed by ? and expr is an expression. The expression language defines the following primitive types:
Object Boolean Char String SByte Byte
Int16 UInt16 Int32 UInt32 Int64 UInt64
Decimal Single Double DateTime TimeSpan Guid
The primitive types correspond to the similarly named types in the System namespace of the .NET Framework Base Class Library. You can also use the nullable form of a value type by writing a ? after the type name (ex: Where="Foo = Int32?(@Foo)").
Therefore, we can rewrite our where clause like so which gets rid of the exception.
<asp:LinqDataSource ID="LinqDataSource2" runat="server"
ContextTypeName="DataClassesDataContext"
Select="new (DummyID, FirstName, LastName)" TableName="DummyTables"
Where="DummyID == Guid(@DummyID)" onselecting="LinqDataSource2_Selecting">
<WhereParameters>
<asp:ControlParameter ControlID="GridView1" Name="DummyID"
PropertyName="SelectedValue" Type="Object" />
</WhereParameters>
</asp:LinqDataSource>
IMO, both these exceptions and a couple of others could probably be avoided if the LinqDataSource had a CancelSelectOnNullParameter and if the TypeCode enum had included the primitive types listed above and nullable value types.
Comments are always welcome!