September 2007 - Posts - Raj Kaimal

September 2007 - Posts

SQL 2005 - Maximum number of characters displayed in each column

This setting in Microsoft SQL server management studio, which has a default setting of 256 characters, caused me to waste almost half an hour yesterday. I was looking in the wrong places trying to troubleshoot my stored procedure and wondering why my data was being truncated. There is no indication in management studio that the text was being truncated either.

To increase the maximum value, open SQL Server management studio and go to

 Tools » Options » Query Results » Results to Text » Maximum number of characters displayed in each column

Note also that there is a "Maximum Characters Retrieved" section under "Results to Grid" section too.

Posted by rajbk | 1 comment(s)
Filed under: ,

Building an RSS feed using LINQ to XML and LINQ to SQL

Version : VS 2008 Beta 2

In this post, I am going to show you how to build a RSS feed of the employees in the NorthWind database using LINQ. Before you proceed, you may want to read Scott's introduction of LINQ to XML over here if you haven't done so already.

To start, lets look at how we can programmatically create the XML document below:

 1: <?xml version="1.0" encoding="utf-8" ?>
 2: <Employees>
 3: <Employee>
 4: <Name>Tom</Name>
 5: <ID>1</ID>
 6: </Employee>
 7: <Employee>
 8: <Name>Jane</Name>
 9: <ID>2</ID>
 10: </Employee>
 11: </Employees>

Without LINQ, we could use the XmlDocument class to create an in-memory tree representation of the document above and write it to the HttpResponse stream like so:

 1: XmlDocument doc = new XmlDocument();
 2:  
 3: XmlDeclaration xmldec = doc.CreateXmlDeclaration("1.0", "utf-8", null);
 4: XmlElement root = doc.DocumentElement;
 5: doc.InsertBefore(xmldec, root);
 6:  
 7: XmlElement employees = doc.CreateElement("Employees");
 8: doc.AppendChild(employees);
 9:  
 10: XmlElement employee1 = doc.CreateElement("Employee");
 11: employees.AppendChild(employee1);
 12:  
 13: XmlElement empID1 = doc.CreateElement("ID");
 14: empID1.InnerText = "1";
 15: employee1.AppendChild(empID1);
 16:  
 17: XmlElement empName1 = doc.CreateElement("Name");
 18: empName1.InnerText = "Tom";
 19: employee1.AppendChild(empName1);
 20:  
 21: XmlElement employee2 = doc.CreateElement("Employee");
 22: employees.AppendChild(employee2);
 23:  
 24: XmlElement empID2 = doc.CreateElement("ID");
 25: empID1.InnerText = "2";
 26: employee1.AppendChild(empID2);
 27:  
 28: XmlElement empName2 = doc.CreateElement("Name");
 29: empName2.InnerText = "Jane";
 30: employee2.AppendChild(empName2);
 31:  
 32: Response.Clear();
 33: doc.Save(Response.Output);
 34: Response.End();

LINQ provides a easier and cleaner way to create XML documents known as functional construction. Using functional construction, you can create all or parts of your in-memory XML tree in a single statement. This is made possible by a constructor in the XElement and XDocument classes that take in a params object (FYI, XElement and XDocument both inherit from type XContainer).

 1: public XElement(XName name, params object[] content);
 2: public XDocument(XDeclaration declaration, params object[] content);

The constructor calls an internal method called AddContentSkipNotify to validate the type of object passed into the params object. From the documentation, parameters can be any of the following:

  • A string, which is added as text content. This is the recommended pattern to add a string as the value of an element; the LINQ to XML implementation will create the internal XText node.
  • An XText, which can have either a string or CData value, added as child content.  This is mainly useful for CData values; using a string is simpler for ordinary string values.
  • An XElement, which is added as a child element
  • An XAttribute, which is added as an attribute
  • An XProcessingInstruction or XComment, which is added as child content
  • An IEnumerable, which is enumerated, and these rules are applied recursively
  • Anything else, ToString() is called and the result is added as text content
  • null, which is ignored

Using functional construction, we can create our in memory XML tree and write it to the response stream like so:

   1: XDocument doc = new XDocument(
   2:     new XDeclaration("2.0", "utf-8", "yes"),
   3:         new XElement("Employees",
   4:             new XElement("Employee",
   5:                 new XElement("Name", "Tom"),
   6:                 new XElement("ID", "1")),
   7:             new XElement("Employee",
   8:                 new XElement("Name", "Tom"),
   9:                 new XElement("ID", "1"))));
  10:  
  11: Response.Clear();
  12: doc.Save(Response.Output);
  13: Response.End();

This code is easier to write compared to the XmlDocument method. It is also easy see the underlying structure of the XML document by looking at the code.

From the documentation above, we know that if we pass in IEnumerable<T> to the XElement constructor, it will get enumerated and the rules will be applied recursively to each element in the collection.

With this knowledge, we could rewrite the code above with a LINQ TO XML query that returns an IEnumerable<XElement> from a collection of anonymous types like so:

   1:         var employees = new[] {
   2:             new {Name = "Tom", ID = 1},
   3:             new {Name = "Jane", ID = 2}
   4:         };
   5:  
   6:         XDocument doc = new XDocument(
   7:             new XDeclaration("2.0", "utf-8", "yes"),
   8:                 new XElement("Employees",
   9:                         //LINQ query that returns IEnumerable<XElement>
  10:                         from e in employees
  11:                         select new XElement("Employee",
  12:                             new XElement("Name", e.Name),
  13:                             new XElement("ID", e.ID)
  14:                         )
  15:                 )
  16:         );
  17:  
  18:         Response.Clear();
  19:         doc.Save(Response.Output);
  20:         Response.End();

Note that  "var employees" above is a collection of anonymous types. The output of this code will produce the same XML document like the previous two code samples did.

Instead of the hard coded employee collection, we could use a LINQ to SQL query that returns an IEnumerable<XElement> of employee names and their description from the database. That is the basic idea behind this post - Using LINQ to SQL to query the database, construct an in-memory XML tree using LINQ to XML by following the RSS specification and finally writing it out to the HttpResponse stream.

The XDocument we are going to construct will follow the RSS 2.0 specification (the minimum required) below:

   1: <?xml version="1.0" encoding="utf-8" standalone="yes"?>
   2: <rss version="2.0">
   3:   <channel>
   4:     <title></title>
   5:     <link></link>
   6:     <description></description>
   7:     <item>
   8:       <title></title>
   9:       <description></description>
  10:       <link></link>
  11:     </item>
  12:     ...
  13:     ...
  14:     ...
  15:     <item>
  16:       <title></title>
  17:       <description></description>
  18:       <link></link>
  19:     </item>
  20:   </channel>
  21: </rss>

Assuming we have created our Nortwind LINQ to SQL object model, we can write the final code in 25 lines(!) like this:

   1:     protected void Page_Load(object sender, EventArgs e)
   2:     {
   3:         NorthwindDataContext context = new NorthwindDataContext();
   4:         Response.Clear();
   5:         Response.ContentType = "text/xml";
   6:  
   7:         XDocument document = new XDocument(
   8:             new XDeclaration("1.0", "utf-8", null),
   9:             new XElement("rss",
  10:                 new XElement("channel",
  11:                     new XElement("title", "Employees of Northwind Traders Inc."),
  12:                     new XElement("link", "http://www.northwindtraders.com"),
  13:                     new XElement("description", "Employees of Northwind Traders Inc. ordered by last name."),
  14:                             from emp in context.Employees
  15:                             orderby emp.LastName
  16:                             select new XElement("item",
  17:                                 new XElement("title", emp.LastName + ", " + emp.FirstName),
  18:                                 new XElement("description", emp.Notes),
  19:                                 new XElement("link", "http://www.northwindtraders.com/employees.aspx?id=" + emp.EmployeeID)
  20:                             )
  21:                     ),
  22:                 new XAttribute("version", "2.0")));
  23:         document.Save(Response.Output);
  24:         Response.End();
  25:     }

Note that the LINQ to SQL query fetches the employee name (LastName + FirstName columns) and the Notes column and creates an XElement called "title" and "description" respectively. We also create a dummy "link" node that points to www.northwindtraders.com since it is part of the requirement of the RSS specs. Once we have our XDocument created, we clear the Response stream, set the content type to text/xml and then "Save" the document to the HttpResponse stream.

This is not the optimal solution though since the DB is queried everytime the page is requested. We obviously have to cache the results on the server for a set amount of time. This can easily be done by calling the .ToList() extension method on the XDocument and storing the results in Cache. I show an example of how to cache the results of a LINQ query here

Note also that you should always HtmlEncode data before rendering it on the browser (which is not shown in the sample code). 

I hope this post has shown you how super easy it is to create XML documents from content in the database using LINQ. To learn more, download VS 2008 Beta 2 and check out the LINQ samples.

Posted by rajbk | 1 comment(s)
Filed under: , , ,

Using the ListView in tiled mode (Part 2) - CSS layout

Using the ListView in tiled mode (Part 1)

Updated 12/01/2007 for VS 2008 RTM

In this second part of my post on customizing the ListView UI, we are going to look at how to consume a Flickr RSS feed and display the feed items in a ListView (tiled mode). The layout will be done using only CSS (no tables). We will also make use of the new DataPager control to display a pager at the top and bottom of the page. Each page will contain 9 photos with 3 photos per row.

flickrtolistview

I am using an RSS feed of some nice photos from Wagner Campelo (I don't know the guy but found him while looking for photos on flickr for this post).

To get started, we add a ListView control and LinqDataSource control to the page and set the DataSource property of the ListView control to the LinqDataSource. We then implement an event handler to handle the Selecting event of the Linqdatasource. We do this to write a custom LINQ expression in the code behind which will fetch the RSS feed and extract the fields we are interested in. This data is assigned to the Result property of the LinqDataSourceSelectEventArgs object. The code behind is shown below:

 1: protected void LinqDataSource1_Selecting(object sender, LinqDataSourceSelectEventArgs e)
 2: {
 3: XDocument rssFeed = XDocument.Load("http://api.flickr.com/services/feeds/photos_public.gne?id=86361978@N00&tags=colors&lang=en-us&format=rss_200");
 4: e.Result = from item in rssFeed.Descendants("item")
 5: select new
 6: {
 7: Title = item.Element("title").Value,
 8: Description = item.Element("description").Value
 9: };
 10: }

Note that we have written an LINQ expression that enumerates all root "item" nodes and extracts the "title" and "description" node values. To learn more about this, read Scott's tutorial on LINQ to XML

The code above is going to parse the RSS feed every time a post back occurs making it non-optimal. What we should do instead is to cache the result of the RSS feed for a set amount of time. The code can be refactored to support caching like so:

 1: public partial class _Default : System.Web.UI.Page
 2: {
 3: private const string FeedUrl = "http://api.flickr.com/services/feeds/photos_public.gne?id=86361978@N00&tags=colors&lang=en-us&format=rss_200";
 4: private const string PhotoCache = "photoCache";
 5:  
 6: protected void LinqDataSource1_Selecting(object sender, LinqDataSourceSelectEventArgs e)
 7: {
 8: e.Result = GetFlickrFeed();
 9: }
 10:  
 11: private object GetFlickrFeed()
 12: {
 13: Object o = Cache[PhotoCache];
 14: if (o == null)
 15: {
 16: XDocument rssFeed = XDocument.Load(FeedUrl);
 17: var photos = from item in rssFeed.Descendants("item")
 18: select new
 19: {
 20: Title = item.Element("title").Value,
 21: Description = item.Element("description").Value
 22: };
 23: o = photos.ToList();
 24: UpdateRefreshDate();
 25: //We are caching for 5 seconds only for demonstration purposes
 26: Cache.Insert(PhotoCache, o, null, DateTime.Now.AddSeconds(5), Cache.NoSlidingExpiration);
 27: }
 28: return o;
 29: }
 30:  
 31: /// <summary>
 32: /// Update the label control in the list view with 
 33: /// the last refreshed time.
 34: /// </summary>
 35: private void UpdateRefreshDate()
 36: {
 37: Label lblLastRefresh = (Label)ListView1.FindControl("lblLastRefresh");
 38: lblLastRefresh.Text = "Last Refreshed at " + DateTime.Now.ToString();
 39: }
 40: }

Note that we call the ToList() method to evaluate the LINQ expression and create a List<T> from the result. Without doing this, we would have stored the Linq expression in cache which would defeat the purpose.

The ListView control supports paging by associating one or more DataPager controls with it. The DataPager, a new control is the default paging control for the ListView control. It can be placed either inside or outside the ListView control. When placed outside the ListView control, you have to specify the ListView Control whose data you wish to page by specifying the PagedControlID property like so: PagedControlID="ListView1". When placed inside a ListView control, you do not need to specify this property - it is implied. The DataPager control is flexible in how you want the pager UI to look like. Note that you can have as many DataPagers as you want placed anywhere on the page!

Moving on to the UI. The code for the aspx page is shown below:

   1: <asp:ListView ID="ListView1" runat="server" GroupItemCount="3" DataSourceID="LinqDataSource1">
   2:     <GroupSeparatorTemplate>
   3:         <div class="groupSeperator">
   4:         </div>
   5:     </GroupSeparatorTemplate>
   6:     <GroupTemplate>
   7:         <div id="itemPlaceholder" runat="server">
   8:         </div>
   9:     </GroupTemplate>
  10:     <ItemTemplate>
  11:         <span class="itemStyle">
  12:             <div class="photoHeading">
  13:                 <%#Eval("Title") %>
  14:             </div>
  15:             <%#Eval("Description") %>
  16:         </span>
  17:     </ItemTemplate>
  18:     <EmptyItemTemplate>
  19:         <span class="itemStyle"></span>
  20:     </EmptyItemTemplate>
  21:     <AlternatingItemTemplate>
  22:         <span class="altItemStyle">
  23:             <div class="photoHeading">
  24:                 <%#Eval("Title") %></div>
  25:             <%#Eval("Description") %></span>
  26:     </AlternatingItemTemplate>
  27:     <LayoutTemplate>
  28:         <div class="layoutRegion">
  29:             <div class="headingRegion">
  30:                 Wagner Campelo
  31:                 <div class="subHeading">
  32:                     Photos from Flickr
  33:                 </div>
  34:             </div>
  35:             <div class="pagerRegion">
  36:                 <asp:DataPager ID="DataPager1" runat="server" PageSize="6">
  37:                     <Fields>
  38:                         <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True"
  39:                             ButtonCssClass="pagerBtn" FirstPageText=" « " NextPageText=" › " PreviousPageText=" ‹ "
  40:                             LastPageText=" » " />
  41:                     </Fields>
  42:                 </asp:DataPager>
  43:             </div>
  44:             <div id="groupPlaceholder" runat="server">
  45:             </div>
  46:             <div class="pagerRegion">
  47:                 <asp:DataPager ID="DataPager2" runat="server" PageSize="6">
  48:                     <Fields>
  49:                         <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True"
  50:                             ButtonCssClass="pagerBtn" FirstPageText=" « " NextPageText=" › " PreviousPageText=" ‹ "
  51:                             LastPageText=" » " />
  52:                     </Fields>
  53:                 </asp:DataPager>
  54:             </div>
  55:             <div class="footerRegion">
  56:                 Copyright © 2007 | 
  57:                 <asp:Label ID="lblLastRefresh" runat="server"></asp:Label>
  58:             </div>
  59:         </div>
  60:     </LayoutTemplate>
  61:     <ItemSeparatorTemplate>
  62:         <div class="itemSeperator">
  63:         </div>
  64:     </ItemSeparatorTemplate>
  65: </asp:ListView>
  66: <asp:LinqDataSource ID="LinqDataSource1" runat="server" OnSelecting="LinqDataSource1_Selecting">
  67: </asp:LinqDataSource>

Note that I am using only div and span tags in the markup and that all div and span tags have a class attribute associated with it. With an aspx markup like this, you have full control of what the UI will look like by making changes to the respective classes in the CSS file.

You can see that the ListView has the GroupItemCount property set to 3 and that I have added two DataPager controls in the LayoutTemplate.

In the UI, I have used dotted lines to separate each photo and each group using CSS. The bottom right of the sample page displays the last time the data was refreshed. To see what the final result will look like, download the sample project file from either location below:

Location 1
Location 2

Posted by rajbk | 5 comment(s)
Filed under: ,

Using the ListView control in Tiled mode (Part 1)

Version : VS 2008 RTM

The ListView control is a data bound control new to the ASP.net web controls collection. The ListView control, from a UI standpoint, gives full control over how the html should be rendered with the help of templates. Scott Guthrie has a great introduction to the ListView control here. If you haven't read it, I strongly recommend you do before proceeding.

For this post, we want to fetch 8 records from the database and display it using the ListView control in a tiled format (3 records/row) using the Employee table in the Northwind database. We shall be using a table layout in this example but keep in mind that you can use any html element or control in your markup and the ListView will render it accordingly. In the second part of this post, you will see an example using a pure css layout with div/span tags.

The ListView control allows you to configure 11 templates in your markup. They are shown below:

LayoutTemplate    
  GroupTemplate  
    ItemTemplate
    AlternatingItemTemplate
    SelectedItemTemplate
    EditItemTemplate
    InsertItemTemplate
    EmptyItemTemplate  
    ItemSeparatorTemplate
  GroupSeparatorTemplate  
EmptyDataTemplate    

Note that the SelectedItemTemplate, EditItemTemplate and InsertItemTemplate will not be used in this post. 

LayoutTemplate
The Layout template is where you specify the elements and controls to render at the beginning and end of the ListView. When working in tiled mode, the ListView requires that you include an element/control with id="groupContainer" and the runat="server" attribute in the Layout template. The tag or control marked with this id will be used as a container to instantiate the GroupTemplate

GroupTemplate
The GroupTemplate is where you specify the elements and controls to render the beginning and end of each Group. This template is required when working in tiled mode. The ListView requires that you include an element/control with id="itemContainer" and the runat="server" attribute. This element or control will be used as a container for instantiating the ItemTemplates and AlternatingTemplates.

Note that when working in any other mode (non tiled mode), the GroupTemplate is optional. Also, in non-tiled mode, if you don't have a GroupTemplate defined, you should have an element/control with id="itemContainer" in the LayoutTemplate.  The code snippets below show both cases.

Tiled Mode

 1: <LayoutTemplate>
 2: <table id="groupContainer" runat="server" border="1">
 3: </table>
 4: </LayoutTemplate>
 5: <GroupTemplate>
 6: <tr id="itemContainer" runat="server">
 7: </tr>
 8: </GroupTemplate>

Non Tiled Mode (without GroupTemplate)

 1: <LayoutTemplate>
 2: <table id="itemContainer" runat="server" border="1">
 3: </table>
 4: </LayoutTemplate>

GroupSeparatorTemplate
The elements and controls to render at the end of each GroupTemplate.

ItemTemplate/AlternatingItemTemplate
The elements and controls to render once for each row and alternate row in the result-set data.

EmptyItemTemplate
The EmptyItemTemplate can be used to populate empty columns in a group with the markup defined in the EmptyItemTemplate. In our scenario, we want to fetch 8 records and display them with 3 records in each row. This means that the last row will have one table cell less than the other rows. The ListView will use the markup defined in an EmptyItemTemplate, if present, to fill in missing columns if any.

ItemSeparatorTemplate
The element and controls to render between each ItemTemplate or AlternatingItemTemplate

EmptyDataTemplate
The element and controls to render when the datasource does not contain any records.

I have created a graphic which shows the ListView markup, the rendered html code and what the UI looks like below. I purposefully added some text in each markup to show you the rendered HTML and which template that HTML came from. I reformatted the rendered html by removing the line breaks from the ItemTemplate contents to save vertical space in the graphic (it is still too large though :) 
ListView Web control (RTM)

Note that I have added a GroupItemCount property to the ListView and set its value to 3. This means that each GroupTemplate will instantiate a max of three ItemTemplate + AlternatingItemTemplates.

By looking at the rendered html, we can see that the contents of the LayoutTemplate is used for the outer shell of the ListView. The markup in the GroupTemplate gets added as the inner node of the control with id="groupPlaceHolder". The markup in the ItemTemplate/ItemSeparatorTemplate then gets added as the inner node to the control with id="itemPlaceHolder". After three records are rendered, the contents of the GroupSeparatorTemplate gets added next and the process repeats. We also see that the contents of the EmptyItemTemplate has been added to the empty column in the third row because we had space for 9 records (3 rows x 3 columns) but we fetched only 8 records.

I have full flexibility over how I want the rendered markup to look like. For example, I am not limited to just two tags in the LayoutTemplate; I could have added, for some reason, a Calendar control above the table tag which would get rendered at the start of the ListView. I could also have added some text below the </table> tag causing it to be rendered at the bottom of the ListView. The only requirement is that an element/control with id="groupPlaceHolder" and an element/control with id="itemPlaceHolder" be present somewhere in the LayoutTemplate and GroupTemplate respectively. In addition, these elements/controls should have the runat="server" attribute.

We can further customize the id of the element/control the ListView looks for by declaring the GroupContainerID and ItemContainerID properties. For example, by specifying GroupContainerID="foo", the ListView will look for a element/control with attribute ID="foo" and runat="server" in the LayoutTemplate instead of one with ID="groupPlaceHolder".

On to the coding portion. The ListView is bound to a LinqDataSource. In the selecting event of the LinqDataSource, I have defined a LINQ expression to fetch the first eight records from the Employee table.

The code behind is shown below:

 1: protected void LinqDataSource1_Selecting(object sender, LinqDataSourceSelectEventArgs e)
 2: {
 3: NorthwindDataContext context = new NorthwindDataContext();
 4: var x = (from c in context.Employees
 5: select new { c.EmployeeID, c.LastName }).Take(8);
 6: e.Result = x;
 7: }

Once the page is run, the custom LINQ expression is run, the data fetched and displayed on the page using the layout defined in the ListView control as shown in the graphic above.

I hope this post has given you a taste of what you can do with the ListView in tiled mode. In the next post, we will be looking at how to make an awesome pure CSS layout using the ListView.

Posted by rajbk | 3 comment(s)

LinqDataSouce - DataItem in code behind

Version : Visual Studio 2008 Beta 2

The following examples shows how to use the GridViewRow.DataItem property to retrieve a property of the underlying object to which the GridViewRow is bound when using the LinqDataSource control.

I have a GridView whose DataSouce is a LinqDataSource. The LinqDataSource has been set to retrieve all records from the Product entity in the Northwind Linq to SQL data model like so:

 1: <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="LinqDataSource1"
 2: OnRowDataBound="GridView1_RowDataBound">
 3: <Columns>
 4: <asp:BoundField DataField="ProductID" HeaderText="ProductID" ReadOnly="True"></asp:BoundField>
 5: <asp:BoundField DataField="ProductName" HeaderText="ProductName" ReadOnly="True"></asp:BoundField>
 6: </Columns>
 7: </asp:GridView>
 8: <asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="NorthwindDataContext"
 9: TableName="Products">
 10: </asp:LinqDataSource>

In this case, getting a property of the underlying data object is easy. The LinqDataSource is aware that each object in the result set is of Type Product (as defined in the Linq to SQL class) and creates it accordingly. So all we have to do is cast the DataItem to type Product and then retrieve the productName:

 1: protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
 2: {
 3: if (e.Row.RowType == DataControlRowType.DataRow)
 4: {
 5: Product p = (Product) e.Row.DataItem;
 6: string productName = p.ProductName;
 7: }
 8: }

The LinqDataSource also allows you to shape the data that is retrieved. In the example below,  I have specified a declarative select to retrieve only a subset of the values from the Products entity - the ProductID and ProductName.

 1: <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="LinqDataSource1"
 2: OnRowDataBound="GridView1_RowDataBound">
 3: <Columns>
 4: <asp:BoundField DataField="ProductID" HeaderText="ProductID" ReadOnly="True"></asp:BoundField>
 5: <asp:BoundField DataField="ProductName" HeaderText="ProductName" ReadOnly="True"></asp:BoundField>
 6: </Columns>
 7: </asp:GridView>
 8: <asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="NorthwindDataContext"
 9: Select="new (ProductID, ProductName)" TableName="Products">
 10: </asp:LinqDataSource>

Since we have defined a custom shape for our result, the LinqDataSouce will create an anonymous type for each object in the resultset like so:

 1: x = {ProductID=17, ProductName=Alice Mutton}

Since we do not know what type to cast the DataItem to, we can use Reflection to retrieve the property. The DataBinder.Eval method already does this so we can retrieve the productName like so:

 1: protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
 2: {
 3: if (e.Row.RowType == DataControlRowType.DataRow)
 4: {
 5: var x = e.Row.DataItem;
 6: string productName = (string) DataBinder.Eval(e.Row.DataItem, "ProductName");
 7: }
 8: }

If you know of a non reflection or better way, please post a comment.

Posted by rajbk | 9 comment(s)
Filed under: , ,

Dynamic String based Queries in LINQ - Dynamic Expression API

Version: Visual Studio 2008 Beta 2

The Dynamic Expression API extends the core LINQ API with the ability to dynamically create string based queries that are constructed at run-time. The API provides

  • Dynamic parsing of strings to produce expression trees (the ParseLambda and Parse methods),
  • Dynamic creation of “Data Classes” (the CreateClass methods), and
  • Dynamic string-based querying through LINQ providers (the IQueryable extension methods).

Assuming I have created a LINQ to SQL entity model for the NorthWind database in VS 2008,

 1: NorthwindDataContext context = new NorthwindDataContext();

I normally would write a query to return all customers ordered by the ContactName in descending order like so:

 1: var x = context.
 2: Customers.
 3: OrderByDescending(c => c.ContactName);

If instead, I wanted to define the Sort column and Sort direction in a string, I could rewrite the query, with the help of the Dynamic Expression API, like so:

 1: string sortExpression = "ContactName DESC";
 2: var x1 = context.
 3: Customers.
 4: OrderBy(sortExpression);

The SQL generated in both cases will be

 1: SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], 
 2: [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax]
 3: FROM [dbo].[Customers] AS [t0]
 4: ORDER BY [t0].[ContactName] DESC

Moving on to another example, If I had a query like so,

 1: DateTime myDate = Convert.ToDateTime("7/26/1996");
 2: var y = context.
 3: Orders.
 4: Where(a => (a.Customer.Country == "Switzerland") && (a.OrderDate < myDate)).
 5: OrderBy(o=> o.OrderDate).
 6: Select(o => new { o.Customer.ContactName, o.Customer.Country, o.OrderDate });

I could use the Dynamic Expression API to rewrite it like this:

 1: var y1 = context.
 2: Orders.
 3: Where("Customer.Country == @0 and OrderDate < @1", "Switzerland", myDate).
 4: OrderBy("OrderDate").
 5: Select("new(Customer.ContactName,Customer.Country, OrderDate)");

Note that, in the query above, the shape of the result is specified as a string. Note also that I have defined what are known as substitution values in the Where statement.

The SQL generated in both cases would be:

 1: exec sp_executesql N'SELECT [t1].[ContactName], [t1].[Country], [t0].[OrderDate] 
 2: FROM [dbo].[Orders] AS [t0]
 3: LEFT OUTER JOIN [dbo].[Customers] AS [t1] ON [t1].[CustomerID] = [t0].[CustomerID]
 4: WHERE ([t1].[Country] = @p0) AND ([t0].[OrderDate] < @p1)
 5: ORDER BY [t0].[OrderDate]'
 6: N'@p0 nvarchar(11),@p1 datetime',
 7: @p0=N'Switzerland',
 8: @p1='1996-07-26 00:00:00:000'

To use the Dynamic Expression API, add the Dynamic.cs class to your project and import the System.Linq.Dynamic namespace.  

To learn more, download the LINQ and language samples for Visual Studio 2008 Beta 2 zip file located at the Visual Studio 2008 samples page.

Posted by rajbk | 12 comment(s)
Filed under: , ,
More Posts