Showing posts with label LINQ. Show all posts
Showing posts with label LINQ. Show all posts

Monday, 27 April 2009

My Crush List of 2009

These are few things which currently I am working on and some technologies which I want to learn in coming months to master these technologies I need your help,

So please post some good tutorials and articles on any of the following topics, if you have any.

1. Silverlight 2.0/3.0

2. Microsoft .NET 2008/2010 and Framework 3.5 SP1/4.0

3. Model View Presenter and Model View Controller Architecture

4. WCF, WSSF incuding Creating custom templates for Implementation Technologies, etc

5. Visual Studio SDK

6. Visual Studio Database Projects (SQl Server 2008 and SQL Server 2005)

7. SQL Server 2008 new Features (Auditing, Change Data Capture and Change Data Tracking)

There are some links which already I am following is given below:

Automatic properties and Object initializers
http://weblogs.asp.net/scottgu/archive/2007/03/08/new-c-orcas-language-features-automatic-properties-object-initializers-and-collection-initializers.aspx

LINQ Tutorials
http://weblogs.asp.net/scottgu/archive/2006/05/14/446412.aspx

Lambda Expression
http://weblogs.asp.net/scottgu/archive/2007/04/08/new-orcas-language-feature-lambda-expressions.aspx

WSSF Home page
http://www.codeplex.com/servicefactory

WSSF Hands on Lab
http://www.codeplex.com/Release/ProjectReleases.aspx?ProjectName=servicefactory&ReleaseId=7846

Thanks
Brij Mohan

Share:

Friday, 21 November 2008

LINQ to XML and LINQ to Objects Basic Sample

In this post I will show how to use LINQ to XML and LINQ to Objects, very basic example with sample code.

image  image

First I have created a XML file which contains the Customer Details, as given below

<?xml version="1.0" encoding="utf-8" ?>
<
customers>
    <
customer>
        <
customerid>ALFKI</customerid>
        <
city>Berlin</city>
        <
age>20</age>
    </
customer>
    <
customer>
        <
customerid>BONAP</customerid>
        <
city>Marseille</city>
        <
age>21</age>
    </
customer>
    <
customer>
        <
customerid>CONSH</customerid>
        <
city>London</city>
        <
age>30</age>
    </
customer>
    <
customer>
        <
customerid>EASTC</customerid>
        <
city>London</city>
        <
age>34</age>
    </
customer>
    <
customer>
        <
customerid>FRANS</customerid>
        <
city>Torino</city>
        <
age>35</age>
    </
customer>
    <
customer>
        <
customerid>LONEP</customerid>
        <
city>Portland</city>
        <
age>40</age>
    </
customer>
    <
customer>
        <
customerid>NORTS</customerid>
        <
city>London</city>
        <
age>25</age>
    </
customer>
    <
customer>
        <
customerid>THEBI</customerid>
        <
city>Portland</city>
        <
age>36</age>
    </
customer>
</
customers>

 

I have also created a class with the same properties which I have given in the XML document above, and populating the same data,

public class Customer
{



public string CustomerID { get; set; }


public string City { get; set; }


public int Age { get; set; }


public static IEnumerable<Customer> CreateCustomers()
{
return new List<Customer>
{
new Customer { CustomerID = "ALFKI", City = "Berlin", Age=20 },
new Customer { CustomerID = "BONAP", City = "Marseille" , Age=21},
new Customer { CustomerID = "CONSH", City = "London", Age=30 },
new Customer { CustomerID = "EASTC", City = "London", Age=34 },
new Customer { CustomerID = "FRANS", City = "Torino", Age=35 },
new Customer { CustomerID = "LONEP", City = "Portland", Age=40 },
new Customer { CustomerID = "NORTS", City = "London" , Age=25 },
new Customer { CustomerID = "THEBI", City = "Portland", Age=26 }
};
}


}



Now I have got the Object ready to query using LINQ with the Same data which I have in my XML Document.



Note above how I'm using the new "Automatic Properties and Object Initializers" feature of C# to define the properties (and avoid having to define a field for them and initialize the Objects). And In all the functions below I am reading the XML Document, using XDocument Class within System.Xml.Linq namespace to open and query document.



First I have to populate the DropDownList in the UI, to display all the Cities, I am reading the Cities from the object alternatively you can also read the same from XML document, both will return the same result. This DropDown will allow the users to select the customers located in the selected City.



public static List<Customer> GetCities()
{
var customers = from customer in Customer.CreateCustomers()
orderby customer.City
select new Customer { City = customer.City };
return customers.ToList();
}



I have also added one more DropDown to let the user to select the DataSource (XML or Object), once both the selection is made, users can click on Get Customers to Get the Customer details. Depending on the DataSource and City, the function below will return the List of Customers wither from XML or the Object.



 



public static List<Customer> GetCustomerFromXML(string city)
{
XDocument xmlDoc = XDocument.Load(HttpContext.Current.Server.MapPath("CustomerXML.xml"));
var customers = from customer in xmlDoc.Descendants("customer")
where customer.Element("city").Value == city
select new Customer
{
CustomerID = customer.Element("customerid").Value,
City = customer.Element("city").Value,
Age = Convert.ToInt32(customer.Element("age").Value)
};
return customers.ToList();
}



Similarly I am writing the function below to read the object, and returning the List<Customer> which we can bind directly to the GridView.



public static List<Customer> GetCustomersFromObject(string city)
{
var customers = from customer in Customer.CreateCustomers()
where customer.City == city
select new Customer
{
CustomerID = customer.CustomerID,
City = customer.City,
Age = customer.Age
};
return customers.ToList();
}



Note: In the functions above the only trick I've made to the LINQ to XML query is to use the "select new Customer" instead of only "select" clause from "select new" (with no type-name).  With this trick I'm returning a sequence of Customer objects that I can pass from class to class, assembly to assembly, and across web-services.



In the code behind of ASPX Page first I have populated the Cities DropDown to List all the cities on Page_Load, then OnClick of the Get Customers  I have written the code to Get the City, and the DataSource from the DropDownList and Call the appropriate method depending on the DataSource.



protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//get all the cities
ddlCity.DataSource = Customer.GetCities();
ddlCity.DataTextField = "city";
ddlCity.DataValueField = "city";
ddlCity.DataBind();
}
}



protected void btnGetCustomers_Click(object sender, EventArgs e)
{
//binding the Customer from Object
if (ddlSource.SelectedValue == "Object")
{
gvCustomerDetails.Visible = true;
lblMessage.Text = "Displaying data from Object";
gvCustomerDetails.DataSource = Customer.GetCustomersFromObject(ddlCity.Text);
gvCustomerDetails.DataBind();
}
//binding the Customer from XML
else if (ddlSource.SelectedValue == "XML")
{
gvCustomerDetails.Visible = true;
lblMessage.Text = "Displaying data from XML";
gvCustomerDetails.DataSource = Customer.GetCustomerFromXML(ddlCity.Text);
gvCustomerDetails.DataBind();
}
else
{
gvCustomerDetails.Visible = false;
lblMessage.Text = "Please select the Data Source";
}
}



Below is my ASPX code which is very much self explanatory, so I have not given much explanation for that, this just for the control name reference.



<html xmlns="http://www.w3.org/1999/xhtml">
<
head runat="server">
<
title></title>
</
head>
<
body>
<
form id="form1" runat="server">
<
h3>
LINQ to Object and LINQ to XML Demo</h3>
<
div>
<
table>
<
tr>
<
td>
<
label for="source" id="lblSource">
Data Source :</label>
</
td>
<
td>
<
asp:DropDownList ID="ddlSource" runat="server">
<
asp:ListItem Text="Select Source" Value="0" Selected="True"></asp:ListItem>
<
asp:ListItem Text="XML" Value="XML"></asp:ListItem>
<
asp:ListItem Text="Object" Value="Object"></asp:ListItem>
</
asp:DropDownList>
</
td>
<
td></td>
</
tr>
<
tr>
<
td>
<
label for="empid" id="lblEmp">
Select City :</label>
</
td>
<
td>
<
asp:DropDownList runat="server" ID="ddlCity"></asp:DropDownList>
</
td>
<
td><asp:Button runat="server" ID="btnGetCustomers" Text="Get Customers"
onclick="btnGetCustomers_Click" /></td>
</
tr>
</
table>
<
br />
<
asp:Label runat="server" ID="lblMessage"></asp:Label>
<
br />
<
asp:GridView ID="gvCustomerDetails" runat="server">
</
asp:GridView>
</
div>
</
form>
</
body>
</
html>



 


You can download the sample code from here.




You can refer my previous posts, to see the Example of LINQ To SQL.




You can see the well formatted code in my ASP.NET Blog.



 



For more knowledge you can refer the post below.



http://weblogs.asp.net/scottgu/archive/2007/08/07/using-linq-to-xml-and-how-to-build-a-custom-rss-feed-reader-with-it.aspx



http://www.c-sharpcorner.com/UploadFile/scottlysle/L2OinCS05242008233051PM/L2OinCS.aspx

Share:

Saturday, 1 November 2008

TwoSelect User Control, Moving Items between ListBox Controls - Part 2

As I promised in this post I am showing you how to implement TwoSelect Control, which I created in my Previous Post

You can download the Complete Source with implementation from here

In this post to get the Available Users and Added Users I am fetching from DataBase using LINQ to SQL, but you can also use either sql or Stored Procedure as per your convenience.

So the first step in Consuming this control in our code is by Creating the Tables, whose structure will look something like this

image

In the User Table I have stored all the User Information, in Group Table I have stored all the Group Details and in UserGroup Table I have related the User and Groups.

In the current project I have not given any screen to enter the User Details or Group Details, as this was out of scope of the current topics, so you can insert the User and Group directly in the Database Tables.

Secondly, Now coming to .NET Code, first I have created a LINQ to SQL and named this as UserGroupData.dbml, and added all the three tables into the designer.

After this I have added the Class to Handle the Data from LINQ to SQL and pass the data to Presentation Layer.

 

In the below given code snippet I am Retrieving all the User who is already present in the Group, this function accepts the groupId as input parameter and return IDataReader to the Presentation Layer, so that we can pass the DataReader directly to the DataSourceAdded Property of the TwoSelect Control and Bind the Data to the Added Users ListBox.

Code Snippet

1:   /// <summary>
2:  /// Gets the group user.
3:  /// </summary>
4:  /// <param name="groupId">The group id.</param>
5:  /// <returns>IDataReader</returns>
6:  public IDataReader GetGroupUser(int groupId)
7:   {
8:   UserGroupDataDataContext data = new UserGroupDataDataContext();
9:   var user = from Grp in data.Groups
10:   join UsrGrp in data.UserGroups on Grp.GroupId equals UsrGrp.GroupId
11:   join Usr in data.Users on UsrGrp.UserId equals Usr.UserId
12:   where Grp.GroupId == groupId
13:   orderby Usr.UserId
14:   select new
15:  {
16:   UserName = Usr.UserName,
17:   GroupName = Grp.GroupName,
18:   UserId = Usr.UserId
19:   };
20:   IDbCommand command = data.GetCommand(user);
21:   command.Connection = data.Connection;
22:   if(command.Connection.State == ConnectionState.Closed)
23:   command.Connection.Open();
24:   IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);
25:   return reader;
26:   }



 




In the below given code snippet I am Retriving all the User who not present in the Group, this function accepts the groupId as input parameter and return IDataReader to the Presentation Layer, so that we can pass the DataReader directly to the DataSourceAvailable Property of the TwoSelect Control and Bind the Data to the Available Users ListBox.






Code Snippet

1:   /// <summary>
2:  /// Users not in the selected group.
3:  /// </summary>
4:  /// <param name="groupId">The group id.</param>
5:  /// <returns>IDataReader</returns>
6:  public IDataReader UserNotInGroup(int groupId)
7:   {
8:   UserGroupDataDataContext data = new UserGroupDataDataContext();
9:   var user = from Grp in data.Groups
10:   join UsrGrp in data.UserGroups on Grp.GroupId equals UsrGrp.GroupId
11:   join Usr in data.Users on UsrGrp.UserId equals Usr.UserId
12:   where Grp.GroupId != groupId
13:   orderby Usr.UserId
14:   select new
15:  {
16:   UserName = Usr.UserName,
17:   GroupName = Grp.GroupName,
18:   UserId = Usr.UserId
19:   };
20:   IDbCommand command = data.GetCommand(user);
21:   command.Connection = data.Connection;
22:   if(command.Connection.State == ConnectionState.Closed)
23:   command.Connection.Open();
24:   IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);
25:   return reader;
26:   }


 



The function below will get all the Group names and Bind the Group DropDown, to display all the Groups so that we can select the Groups whose user I want to manage.






Code Snippet

1:   /// <summary>
2:  /// Gets all group.
3:  /// </summary>
4:  /// <returns>IDataReader</returns>
5:  public IDataReader GetAllGroup()
6:   {
7:   UserGroupDataDataContext data = new UserGroupDataDataContext();
8:   var groups = from Grp in data.Groups
9:   orderby Grp.GroupName
10:   select new
11:   {
12:   GroupId = Grp.GroupId,
13:   GroupName = Grp.GroupName
14:   };
15:   IDbCommand command = data.GetCommand(groups);
16:   command.Connection = data.Connection;
17:   if (command.Connection.State == ConnectionState.Closed)
18:   command.Connection.Open();
19:   IDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);

20:   return reader;
21:   }


 


This function will update the DataBase once we have selected the Users in a particular Group.





Code Snippet

1:   /// <summary>
2:  /// Saves the group user.
3:  /// </summary>
4:  /// <param name="group">The group.</param>
5:  public void SaveGroupUser(List<UserGroup> usrGroup)
6:   {
7:   UserGroupDataDataContext data = new UserGroupDataDataContext();

8:   //first delete all the existing user data from User Group
9:  foreach (UserGroup match in usrGroup)
10:   {
11:   var deleteUserGroup = from userGroups in data.UserGroups
12:   where userGroups.UserId == match.UserId
13:   select userGroups;
14:   foreach (var userGroup in deleteUserGroup)
15:   data.UserGroups.DeleteOnSubmit(userGroup);

16:   data.SubmitChanges();
17:   }

18:   //MISSING : Logic to implement Save new Data related to User and Group
19: 
20:   }


 



The same things you can do without using the LINQ to SQL either by writing the Stored Procedure or using the SQL Queries.



I am giving below the sample stored procedure which can replace the function GetGroupUser and GetUserNoInGroup



  • GetGroupUser

   1:  SET ANSI_NULLS ON

   2:  GO

   3:  SET QUOTED_IDENTIFIER ON

   4:  GO

   5:  CREATE PROCEDURE [dbo].[GetGroupUser]

   6:      

   7:      (

   8:      @GroupId int

   9:      )

  10:      

  11:  AS

  12:      SET NOCOUNT ON 

  13:      

  14:      SELECT 

  15:          Usr.UserName, 

  16:          Grp.GroupName,

  17:          Usr.UserId 

  18:      From  

  19:          GROUPS Grp

  20:      INNER JOIN 

  21:          UserGroup UsrGrp

  22:      ON 

  23:          Grp.GroupId = UsrGrp.GroupId

  24:      INNER JOIN USERS Usr ON

  25:          UsrGrp.UserId = Usr.UserId

  26:      WHERE 

  27:          Grp.GroupId=@GroupId

  28:      ORDER BY Usr.UserId

  29:      

  30:      RETURN

 



  • GetUserNotInGroup


   1:  SET ANSI_NULLS ON

   2:  GO

   3:  SET QUOTED_IDENTIFIER ON

   4:  GO

   5:  ALTER PROCEDURE [dbo].[UserNotInGroup]

   6:      

   7:      (

   8:      @GroupId int

   9:      )

  10:      

  11:  AS

  12:      SET NOCOUNT ON

  13:      SELECT 

  14:          Usr.UserName,

  15:          Usr.UserId, 

  16:          Grp.GroupName 

  17:      From  

  18:          GROUPS Grp

  19:      INNER JOIN 

  20:          UserGroup UsrGrp

  21:      ON 

  22:          Grp.GroupId = UsrGrp.GroupId

  23:      INNER JOIN USERS Usr ON

  24:          UsrGrp.UserId = Usr.UserId

  25:      WHERE 

  26:          Grp.GroupId!=@GroupId

  27:      ORDER BY Usr.UserId

  28:      

  29:      RETURN



 


 



Third, I have included the UserControl in my Project, and added in Default.asp page simply by Drag and Drop.




Also I have added one DropDown Control to get the List of all the Groups and Added a Save Button to Save the Changes back to the database.




After designing the Page will look something similar to this



image


 

 

Now in Code Behind I tried to implement only the logic which is related to the TwoSelect User controls,




Code Snippet

1:   public partial class _Default : System.Web.UI.Page
2:  {
3:   UserData data = new UserData();

4:   private int GetGroupId
5:   {
6:   get { return Convert.ToInt32(ddlGroup.SelectedValue); }
7:   }
8:   /// <summary>
9:  /// Handles the Load event of the Page control.
10:  /// </summary>
11:  /// <param name="sender">The source of the event.</param>
12:  /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
13:  protected void Page_Load(object sender, EventArgs e)
14:   {
15:   if (!IsPostBack)
16:   {
17:   ddlGroup.DataSource = data.GetAllGroup();
18:   ddlGroup.DataTextField = "GroupName";
19:   ddlGroup.DataValueField = "GroupId";
20:   ddlGroup.DataBind();
21:   ListItem item = new ListItem();
22:   item.Text = "Please Select";
23:   item.Value = "0";
24:   ddlGroup.Items.Insert(0,item);
25:   }
26:   }

27:   protected void ddlGroup_SelectedIndexChanged(object sender, EventArgs e)
28:   {
29:   //Bind the User Control Available List Box
30:  uclTwoSelect.DataSourceAvailable = data.GetGroupUser(this.GetGroupId);
31:   uclTwoSelect.DataTextFieldAvailable = "UserName";
32:   uclTwoSelect.DataValueFieldAvailable = "UserId";

33:   //Bind the User Control User Already Added List Box
34:  uclTwoSelect.DataSourceAdded = data.UserNotInGroup(this.GetGroupId);
35:   uclTwoSelect.DataTextFieldAdded = "UserName";
36:   uclTwoSelect.DataValueFieldAdded = "UserId";

37:   uclTwoSelect.BindControl();
38:   }

39:   /// <summary>
40:  /// Saves the User associated with the Groups.
41:  /// </summary>
42:  /// <param name="sender">The source of the event.</param>
43:  /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
44:  protected void btnSave_Click(object sender, EventArgs e)
45:   {
46:   UserGroup user = new UserGroup();
47:   List<UserGroup> group = new List<UserGroup>();
48:   ListItemCollection userGroup = uclTwoSelect.AddedItems;
49:   foreach (ListItem item in userGroup)
50:   {
51:   user.GroupId = Convert.ToInt32(ddlGroup.SelectedValue);
52:   user.UserId = Convert.ToInt32(item.Value);

53:   group.Add(user);
54:   }

55:   data.SaveGroupUser(group);
56:   }
57:   }



You can see in the code above I am binding the DropDown List of the Group and on SelectedIndexChanged even of the DropDown I am Binding the twoSelect Controls Data, with the DataSourceAvailable and DataSourceAdded Properties.



Sorry for the Code Formatting Guys, but you can always refer my asp.net weblog for my neat and clear code formatting.



This is just the one of the implementation you can download the Control and its implementation code from here and Enhance the Control.


 


References


http://www.west-wind.com/WebLog/posts/141435.aspx


http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listbox.aspx


http://msdn.microsoft.com/en-us/library/fb3w5b53(VS.85).aspx


 


Thanks


Brij Mohan

Share:

Saturday, 27 September 2008

ASP.NET MVC - Presentation in Bangalore 26-Sept-2008

Below are slides + demos of the presentation I've given on 26-Sept-2008. Feel free to re-use and take advantage of them however you want.

Download the Demo Project from

http://weblogs.asp.net/blogs/brijmohan/DemoPresentation/PhoneBook.zip

Download the Presentation from

http://weblogs.asp.net/blogs/brijmohan/DemoPresentation/A%20Brief%20overview%20of%20ASP.NET%20MVC.zip

Thanks

Brij Mohan
Share:

Friday, 8 February 2008

Using LINQ with ASP.NET

One of the new things I’m super excited about right now is the LINQ family of technologies that are starting to come out (LINQ, DLINQ, XLINQ and others soon).

LINQ will be fully integrated with the next release of Visual Studio (code-name: Orcas) and it will include some very cool framework and tool support (including full intellisense and designer support). Last week the LINQ team released the May CTP drop of LINQ that you can download from here. What is cool about this CTP is that it works with VS 2005, and allows you to start learning more about it immediately. It incorporates a bunch of customer feedback (for example: support for stored procedures in DLINQ), and also includes a built-in ASP.NET Web-Site Project to enable you to leverage it with ASP.NET apps (note: you can also use LINQ with the new VS 2005 Web Application Project option as well).

Note: LINQ, DLINQ and XLINQ will be fully supported in both C# and VB. I am using C# for the example belows.

Step 0: Creating a C# LINQ ASP.NET Web Site

To create a new ASP.NET Web Site that can use LINQ/DLINQ/XLINQ and the new C# 3.0 language features, choose File->New Web Site in VS and select the “LINQ ASP.NET Web Site Template”:

This will create a web-site project with the following files in-it by default:

Note that it includes a number of LINQ assemblies in the bin folder. It also adds the following setting to the app’s web.config file which tells both VS and ASP.NET to use the C# 3.0 compiler to compile and run the app:

<system.codedom>

<compilers>

<compiler language="c#;cs;csharp"

extension=".cs"

type="Microsoft.CSharp.CSharp3CodeProvider, CSharp3CodeDomProvider"/>

</compilers>

</system.codedom>

Note that the C# 3.0 compiler and CodeDOM provider can run side-by-side with the C# 2.0 versions (so you don’t have to worry about it breaking VS or ASP.NET when you install it).

Step 1: Creating your first ASP.NET page using LINQ

Create a new page called Step1.aspx. Within the .aspx page add a GridView control like so:

<%@ Page Language="C#" CodeFile="Step1.aspx.cs" Inherits="Step1" %>

<html>

<body>

<form id="form1" runat="server">

<div>

<h1>City Names</h1>

<asp:GridView ID="GridView1" runat="server">

</asp:GridView>

</div>

</form>

</body>

</html>

Within the code-behind file we’ll then write the canonical “hello world” LINQ sample – which involves searching and ordering a list of strings:


using System;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Query;

public partial class Step1 : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

string[] cities = { "London", "Amsterdam", "San Francisco", "Las Vegas",

"Boston", "Raleigh", "Chicago", "Charlestown",

"Helsinki", "Nice", "Dublin" };

GridView1.DataSource = from city in cities

where city.Length > 4

orderby city

select city.ToUpper();

GridView1.DataBind();

}

}

In the above sample I’ve created an array of strings listing the cities I’ve visited from Jan->May of this year. I’m then using a LINQ query expression against the array. This query expression returns all cities where the city name is greater than 4 characters, and orders the result in alphabetical order and transforms those city names into upper case.

LINQ queries return results of type: IEnumerable<T> -- where <T> is determined by the object type of the “select” clause. In the above sample “city” is a string, so the type-safe result is a generics based collection like so:

IEnumerable<string> result = from city in cities

where city.Length > 4

orderby city

select city.ToUpper();

Because ASP.NET controls already support databinding to any IEnumerable collection, we can easily assign this LINQ query result to the GridView and call its DataBind() method to generate this page output result:

Note that instead of using the GridView control I could have just as easily used the <asp:repeater>, <asp:datalist>, <asp:dropdownlist>, or any other ASP.NET list control (both those built-into the product or ones built by other developers). For the purposes of these samples I’m just going to use the <asp:gridview> -- but again know that you can use any.

Step2: Using Richer Collections

Searching an array of strings is not terribly interesting (although sometimes actually useful). More interesting would be the ability to search and work against richer collections of our own making. The good news is that LINQ makes this easy. For example, to better track trips I can create a simple class called “Location” in my project below:

using System;

public class Location

{

// Fields

private string _country;

private int _distance;

private string _city;

// Properties

public string Country

{

get { return _country; }

set { _country = value; }

}

public int Distance

{

get { return _distance; }

set { _distance = value; }

}

public string City

{

get { return _city; }

set { _city = value; }

}

}

This exposes 3 public properties to track the County, City name and Distance from Seattle. I can then create a Step2.aspx file with a GridView control that defines 3 columns like so:

<%@ Page Language="C#" CodeFile="Step2.aspx.cs" Inherits="Step2" %>

<html>

<body>

<form id="form1" runat="server">

<h1>Cities and their Distances</h1>

<asp:GridView ID="GridView1" AutoGenerateColumns="false" runat="server">

<Columns>

<asp:BoundField HeaderText="Country" DataField="Country" />

<asp:BoundField HeaderText="City" DataField="City" />

<asp:BoundField HeaderText="Distance from Seattle" DataField="Distance" />

</Columns>

</asp:GridView>

</form>

</body>

</html>

I can then populate a collection of Location objects and databind it to the Grid in my code-behind like so:

using System;

using System.Collections.Generic;

using System.Web;

using System.Query;

public partial class Step2 : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

List<Location> cities = new List<Location>{

new Location { City="London", Distance=4789, Country="UK" },

new Location { City="Amsterdam", Distance=4869, Country="Netherlands" },

new Location { City="San Francisco", Distance=684, Country="USA" },

new Location { City="Las Vegas", Distance=872, Country="USA" },

new Location { City="Boston", Distance=2488, Country="USA" },

new Location { City="Raleigh", Distance=2363, Country="USA" },

new Location { City="Chicago", Distance=1733, Country="USA" },

new Location { City="Charleston", Distance=2421, Country="USA" },

new Location { City="Helsinki", Distance=4771, Country="Finland" },

new Location { City="Nice", Distance=5428, Country="France" },

new Location { City="Dublin", Distance=4527, Country="Ireland" }

};

GridView1.DataSource = from location in cities

where location.Distance > 1000

orderby location.Country, location.City

select location;

GridView1.DataBind();

}

}

The above code-behind shows off a few cool features. The first is the new C# 3.0 support for creating class instances, and then using a terser syntax for setting properties on them:

new Location { City="London", Distance=4789, Country="UK" }

This is very useful when instantiating and adding classes within a collection like above (or within an anonymous type like we’ll see later). Note that rather than use an array this time, I am using a Generics based List collection of type “Location”. LINQ supports executing queries against any IEnumerable<T> collection, so can be used against any Generics or non-Generics based object collections you already have.

For my LINQ query I’m then returning a collection of all cities that are more than 1000 miles away from Seattle. I’ve chosen to order the result in alphabetical order – first by country and then by city name. The result of this LINQ query is again dictated by the type of the “location” variable – so in this case of type “Location”:

IEumerable<Location> result = from location in cities

where location.Distance > 1000

orderby location.Country, location.City

select location;

When I databind this result against the GridView I get a result like so:

Step 3: Refactoring the City Collection Slightly

Since we’ll be re-using this collection of cities in several other samples, I decided to encapsulate my travels in a “TravelOrganizer” class like so:

using System;

using System.Collections.Generic;

public class TravelOrganizer

{

public List<Location> PlacesVisited

{

get

{

List<Location> cities = new List<Location>{

new Location { City="London", Distance=4789, Country="UK" },

new Location { City="Amsterdam", Distance=4869, Country="Netherlands" },

new Location { City="San Francisco", Distance=684, Country="USA" },

new Location { City="Las Vegas", Distance=872, Country="USA" },

new Location { City="Boston", Distance=2488, Country="USA" },

new Location { City="Raleigh", Distance=2363, Country="USA" },

new Location { City="Chicago", Distance=1733, Country="USA" },

new Location { City="Charleston", Distance=2421, Country="USA" },

new Location { City="Helsinki", Distance=4771, Country="Finland" },

new Location { City="Nice", Distance=5428, Country="France" },

new Location { City="Dublin", Distance=4527, Country="Ireland" }

};

return cities;

}

}

}

This allows me to then just write the below code in our code-behind to get the same result as before:

using System;

using System.Collections.Generic;

using System.Web;

using System.Web.UI;

using System.Query;

public partial class Step3 : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

TravelOrganizer travel = new TravelOrganizer();

GridView1.DataSource = from location in travel.PlacesVisited

where location.Distance > 1000

orderby location.Country, location.City

select location;

GridView1.DataBind();

}

}

What is really cool about LINQ is that it is strongly-typed. What this means is that:

1) You get compile-time checking of all queries. Unlike SQL statements today (where you typically only find out at runtime if something is wrong), this means you will be able to check during development that your code is correct (for example: if I wrote “distanse” instead of “distance” above the compiler would catch it for me).

2) You will get intellisense within VS (and the free Visual Web Developer) when writing LINQ queries. This makes both typing faster, but also make it much easier to work against both simple and complex collection and datasource object models.

Step 4: Skipping and Taking using .NET Standard Query Operators

LINQ comes with built-in support for many built-in Standard Query Operators. These can be used within code by adding a “using System.Query” statement at the top of a class file, and can be applied to any sequence of data. For example, if I wanted to list cities in order of distance and list the 2nd->6th farthest away cities I could write my code-behind file like so:

using System;

using System.Web.UI;

using System.Query;

public partial class Step4 : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

TravelOrganizer travel = new TravelOrganizer();

GridView1.DataSource = (from location in travel.PlacesVisited

orderby location.Distance descending

select location).Skip(1).Take(5);

GridView1.DataBind();

}

}

Note how I am ordering the result by the distance (farthest to least). I am then using the “Skip” operator to skip over the first city, and the "Take" operator to only return the remaining 5.

What is really powerful is that the .NET Standard Query Operators are not a hard-coded list, and can be added to and replaced by any developer. This enables very powerful domain specific implementations. For example, when the Skip() and Take() operators are used with DLINQ – it translates the calls into back-end SQL logic that performs server-side paging (so that only a few rows are returned from the SQL database – regardless of whether it is from a table with 100,000+ rows of data). This means that you will be able to trivially build efficient web data paging over lots of relational data (note: until then you can use the techniques listed here).

Step 5: More Fun with .NET Standard Query Operators

In addition to returning sequences of data, we can use .NET Standard Query Operators to return single or computed results of data. The below samples show examples of how to-do this:

<%@ Page Language="C#" CodeFile="Step5.aspx.cs" Inherits="Step5" %>

<html>

<body>

<form id="form1" runat="server">

<div>

<h1>Aggregate Value Samples</h1>

<div>

<b>Farthest Distance City:</b>

<asp:Label ID="MaxCityNameTxt" runat="server" Text="Label"></asp:Label>

<asp:Label ID="MaxCityDistanceTxt" runat="server" Text="Label"></asp:Label>

</div>

<div>

<b>Total Travel Distance (outside of US):</b>

<asp:Label ID="TotalDistanceTxt" runat="server" Text="Label"></asp:Label>

</div>

<div>

<b>Average Distance:</b>

<asp:Label ID="AverageDistanceTxt" runat="server" Text="Label"></asp:Label>

</div>

</div>

</form>

</body>

</html>

Step5.aspx.cs code-behind file:

using System;

using System.Collections.Generic;

using System.Web.UI;

using System.Query;

public partial class Step5 : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

TravelOrganizer travel = new TravelOrganizer();

//

// Calculate farthest city away

Location farthestCity = (from location in travel.PlacesVisited

orderby location.Distance descending

select location).First();

MaxCityNameTxt.Text = farthestCity.City;

MaxCityDistanceTxt.Text = "(" + farthestCity.Distance + " miles)";

//

// Calculate total city distances of all cities outside US

int totalDistance = (from location in travel.PlacesVisited

where location.Country != "USA"

select location).Sum(loc => loc.Distance);

TotalDistanceTxt.Text = totalDistance + " miles";

//

// Calculate average city distances of each city trip

double averageDistance = travel.PlacesVisited.Average(loc => loc.Distance);

AverageDistanceTxt.Text = averageDistance + " miles";

}

}

Note that the last two examples above use the new Lambda Expression support – which enable fragments of code (like delegates) that can operate on top of data to compute a result. You can build your own .NET Query Operators that use these (for example: you could build domain specific ones to calculate shipping costs or payroll tax). Everything is strongly-typed, and will support intellisense and compilation checking support.

The output of the above sample looks like so:

Step 6: Anonymous Types

One of the new C# and VB language features that LINQ can take advantage of is support for “Anonymous Types”. This allows you to easily create and use type structures inline without having to formally declare their object model (instead it can be inferred by the initialization of the data). This is very useful to “custom shape” data with LINQ queries.

For example, consider a scenario where you are working against a database or strongly-typed collection that has many properties – but you only really care about a few of them. Rather than create and work against the full type, it might be useful to only return those properties that you need. To see this in action we’ll create a step6.aspx file like so:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Step6.aspx.cs" Inherits="Step6" %>

<html>

<body>

<form id="form1" runat="server">

<div>

<h1>Anonymous Type</h1>

<asp:GridView ID="GridView1" runat="server">

</asp:GridView>

</div>

</form>

</body>

</html>

And within our code-behind file we’ll write a LINQ query that uses anonymous types like so:

using System;

using System.Web.UI;

using System.Query;

public partial class Step6 : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

TravelOrganizer travel = new TravelOrganizer();

GridView1.DataSource = from location in travel.PlacesVisited

orderby location.City

select new {

City = location.City,

Distance = location.Distance

};

GridView1.DataBind();

}

}

Note that instead of returning a “location” from our select clause like before, I am instead creating a new anonymous type that has two properties – “City” and “Distance”. The types of these properties are automatically calculated based on the value of their initial assignment (in this case a string and an int), and when databound to the GridView produce an output like so:

Step 7: Anonymous Types (again)

The previous sample showed a basic example of using anonymous types to custom-shape the output of a LINQ query. The below sample provides a richer and more practical scenario. It transforms our list of cities into a hierarchical result collection – where we group the results around countries using an anonymous type that we define that contains the country name, a sub-collection list of city details, and the sum of the total distance of all cities within the country (computed using a lambda expression like we demonstrated in step5 above):

using System;

using System.Web.UI;

using System.Query;

public partial class Step7 : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

TravelOrganizer travel = new TravelOrganizer();

GridView1.DataSource = from location in travel.PlacesVisited

group location by location.Country into loc

select new {

Country = loc.Key,

Cities = loc,

TotalDistance = loc.Sum(dist => dist.Distance)

};

GridView1.DataBind();

}

}

The GridView on our .aspx page is then defined like so:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Step7.aspx.cs" Inherits="Step7" %>

<html>

<body>

<form id="form1" runat="server">

<div>

<h1>Groupings with Anonymous Classes</h1>

<asp:GridView ID="GridView1" AutoGenerateColumns="false" runat="server">

<Columns>

<asp:BoundField HeaderText="Country" DataField="Country" />

<asp:TemplateField HeaderText="Cities">

<ItemTemplate>

<asp:BulletedList ID="BulletedList1" runat="server"

DataSource='<%#Eval("Cities")%>' DataValueField="City"/>

</ItemTemplate>

</asp:TemplateField>

<asp:BoundField HeaderText="Total Distance" DataField="TotalDistance" />

</Columns>

</asp:GridView>

</div>

</form>

</body>

</html>

Notice how I’ve added a GridView templatefield column for the “Cities” column – and within that I’ve then added an <asp:bulletedlist> control (a new control built-in with ASP.NET 2.0) that databinds its values from the cities property of the hierarchical result we created using our LINQ query above. This generates output like so:

Note that all of the databind syntax and hierarchical binding support in the .aspx page above is fully supported in ASP.NET 2.0 today – so you can use this same technique with any existing app you have now. What is new (and I think very cool) is the data shaping capabilities provided by anonymous types and LINQ – which makes binding hierarchical data against ASP.NET controls very easy.

Next Steps

All of my samples above were against in-memory collections. They show you how you will be able to use LINQ against any .NET object model (includes all the ones you have already).

For example, if you use DLINQ to generate a Northwinds database mapping of Suppliers and their Products (no code is required to set this up), the below code is all you need to write to obtain and databind a hierarchical database result against a GridView like we did above (note: we are using the same data-shaping technique as our previous sample to only require fetching two columns from the database, and automatically join the products of each supplier as a hierarchical group result):

using System;

using System.Query;

public partial class Data_Data2 : System.Web.UI.Page

{

protected void Page_Load(object sender, EventArgs e)

{

Northwind db = new Northwind();

GridView1.DataSource = from x in db.Suppliers

where x.Country == "USA"

orderby x.Country

select new {

x.CompanyName,

x.Country,

x.Products

};

GridView1.DataBind();

}

}

No custom SQL syntax or code is required – this is all that needs to be written to efficiently fetch and populate hierarchical data now (note: only the rows and columns needed will be fetched -- DLINQ can use the remote function support within LINQ so that it does not need to materialize or fetch the full database table or all columns from a row). And it is all type-safe, with full compiler checking, intellisense, and debugging supported.

Even better, the ability to plug-in new LINQ providers (of which DLINQ and XLINQ are just two examples) is completely open – so developers who either build or use existing data providers today (for example: O/R database mappers) can easily integrate their implementations with LINQ to have a seamless developer experience. Once you know LINQ you will know all the basics needed to program against any of them.

Summary

Hopefully this provides a glimpse of some of the cool new things coming. You can try it all out today by downloading the May CTP drop of LINQ today from here. You can also download and run all of the samples built above from this .ZIP file here.

Original Post can be found at http://weblogs.asp.net/scottgu/archive/2006/05/14/Using-LINQ-with-ASP.NET-_2800_Part-1_2900_.aspx

Share: