A group blog from members of the VB team
Happy holidays! It's been a long time since I've written a post, so I figure I can bring in the new year answering some great questions submitted by you.
Just this week someone gave me this feedback: "I am having a difficult time finding information to help me adapt to LINQ in my webforms. I am hoping that someone from the team can offer a direction. "
You bet! We have a lot of attention to LINQ and Forms-over-data in VB in our learning content, but we're lacking content with attention to LINQ and Web-based Forms-over-data.
There are a number of great innovations in the Web space that make it easy to leverage LINQ's querying capabilities and mesh that with the richness and flexibility of Web-based UI. It's easy.
There are a few concepts you should learn or know about to get started:
The first post will cover the simplest Web form that will demonstrate this end to end span of concepts. I'll then take input from you to add features and expand on this sample in future posts.
Here's a sample of the initial desired Web form output - a very simple Employee list report for an HR application - admittedly it's bare bones and in need of UI design love:
EmployeeID: 2 Andrew Fuller Andrew received his BTS commercial in 1974 and a Ph.D. in international marketing from the University of Dallas in 1981. He is fluent in French and Italian and reads German. He joined the company as a sales representative, was promoted to sales manager in January 1992 and to vice president of sales in March 1993. Andrew is a member of the Sales Management Roundtable, the Seattle Chamber of Commerce, and the Pacific Rim Importers Association. EmployeeID: 1 Nancy Davolio Education includes a BA in psychology from Colorado State University in 1970. She also completed "The Art of the Cold Call." Nancy is a member of Toastmasters International.
EmployeeID: 2 Andrew Fuller Andrew received his BTS commercial in 1974 and a Ph.D. in international marketing from the University of Dallas in 1981. He is fluent in French and Italian and reads German. He joined the company as a sales representative, was promoted to sales manager in January 1992 and to vice president of sales in March 1993. Andrew is a member of the Sales Management Roundtable, the Seattle Chamber of Commerce, and the Pacific Rim Importers Association.
EmployeeID: 1 Nancy Davolio Education includes a BA in psychology from Colorado State University in 1970. She also completed "The Art of the Cold Call." Nancy is a member of Toastmasters International.
If you are pretty familiar with Visual Studio I expect this will take about 10-15 minutes to walk through on your own machine.
- make sure you have Visual Studio 2008 or Visual Web Developer 2008 Express installed. Express Editions are available for download here. - make sure you have SQL Server 2005 Express installed and running. It typically gets installed by default with VS or VS Express, however, you can also install it from here. -if you don't have Northwind.mdf on your machine, download it from the attached files on this post.
First we're going to add the database to our project and create necessary classes to use the database in LINQ (using Linq to SQL). Note, you could choose to skip this step and create your own custom LINQ query to any other data source.
Now that we've added the database to the Web site and created necessary LINQ to SQL classes, it's time to create some UI and wire up the data to the UI. I won't do anything too fancy - just repeat data bound labels in a DataList (you could replace this with GridView, FormView or choose your favorite control).
The LinqDataSource needs to be wired up to the underlying LINQ data. In this case data is provided by any DataContext object or query over an object of the NorthwindDataClasses type (a LINQ to SQL file). The DataList then simply needs to use the LinqDataSource as the data source, and display data from bound fields using traditional Eval("") statements. The designer will generate a set of defaults for you if you use the Smart Tags. Let's give it a shot with defaults, and then we can fine tune it from there.
Here is the resulting mark up for the LinqDataSource as seen in "Source" view. Note how the ContextTypeName="NorthwindDataClassesDataContext" -- this matches the name of the type we created in the designer (the code gen appends "DataContext" to the end -- whew that's long!). The TableName is set to the Table or Property we want to display -- Employees in this case. You could use this pattern to bind to any DataContext type and class property within.
<asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="NorthwindDataClassesDataContext" TableName="Employees"> </asp:LinqDataSource>
Now let's wire up the DataList to the LinqDataSource. The nice thing here is the DataList only cares about the field names returned from the LINQ query via the LinqDataSource -- this shields you as you continue to refine the fields and row results of your dynamic LINQ queries.
The wizard will create a series of bound labels by default. You can use the designer in edit mode to get the specific fields, look and feel you want. TIP: This is typically where I drop in the html mark up "Source" view. In my example, I'll simply show the full name, notes, and have a place holder to show an employee photo image. I also format the data in a two column table.
If you look at the DataList mark up, you see the ItemTemplate contains a number of bound labels. Binding to data from the query is simply a matter of typing in <%# Eval("YOURFIELDNAME") %> in your server control fields using classic ASP-style & VB data binding eval statements. This gives you a lot of flexibility to display just the data you want, formatted how you want. Here's my customization:
<div> <asp:DataList ID="DataList1" runat="server" DataKeyField="EmployeeID" DataSourceID="LinqDataSource1"> <HeaderTemplate> <table> </HeaderTemplate> <ItemTemplate> <tr> <td> <img src="PLACEHOLDER.jpg" class="" style="border: 4px solid white" alt='Photo Number XXX' /> <br /><br /> </td> <td> EmployeeID: <asp:Label ID="EmployeeIDLabel" runat="server" Text='<%# Eval("EmployeeID") %>' /> <br /> <asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("FirstName") & " " & Eval("LastName") %>' /> <br /> <asp:Label ID="NotesLabel" runat="server" Text='<%# Eval("Notes") %>' /> </td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:DataList> </div>
The technique above provides a zero-code method for binding Web forms to LINQ data. However, you might be asking yourself, where is the LINQ and VB here? It's true the LinqDataSource hides all the querying code and constrains what you can do via the designer. This is fine for some simple cases, but the real power of LINQ is being able to use your own free form queries and VB logic. The good news is LinqDataSource supports using your own LINQ queries using the LinqDataSource.Selecting event. This is your hook to tell the control exactly what query should be used. It's easy. Here's how:
In my example I will query over Northwind employees, define a custom expression column called FullName (=First + Last), filter by full name starting with A or N, and sort by last name. Note I'm creating aliases for each property and hence the query is now an anonymous type -- and the schema is now custom vs. my default NorthwindDataContext with all (*) columns. TIP: if you're getting runtime errors when you try this make sure all the fields expected by your Web form are there -- e.g. if the form is expecting "EmployeeID" make sure your query Selects it.
Protected Sub LinqDataSource1_Selecting(ByVal sender As Object, ByVal e _ As System.Web.UI.WebControls.LinqDataSourceSelectEventArgs) _ Handles LinqDataSource1.Selecting Dim northwind As New NorthwindDataClassesDataContext 'custom anonymous LINQ query Dim query = From emp In northwind.Employees _ Select emp.EmployeeID, emp.FirstName, emp.LastName, emp.Notes, _ FullName = emp.FirstName & " " & emp.LastName _ Where FirstName.ToUpper.StartsWith("A") Or FirstName.ToUpper.StartsWith("N") _ Order By FullName 'sets LinqDataSource query equal to custom query. 'use data binding expressions to look up aliased fields above. e.Result = query End Sub
You can run the app again and see the custom query is working -- only two rows are returned -- Andrew Fuller and Nancy Davolio. We could also tweak the markup to make use of our new aliased expression column -- "FullName". Here's how that would look in the DataList:
<asp:DataList ID="DataList1" runat="server" DataKeyField="EmployeeID" DataSourceID="LinqDataSource1"> <HeaderTemplate> <table> </HeaderTemplate> <ItemTemplate> <tr> <td> <img src="PLACEHOLDER.jpg" class="" style="border: 4px solid white" alt='Photo Number XXX' /> <br /><br /> </td> <td> EmployeeID: <asp:Label ID="EmployeeIDLabel" runat="server" Text='<%# Eval("EmployeeID") %>' /> <br /> <asp:Label ID="LastNameLabel" runat="server" Text='<%# Eval("FullName") %>' /> <br /> <asp:Label ID="NotesLabel" runat="server" Text='<%# Eval("Notes") %>' /> </td> </tr> </ItemTemplate> <FooterTemplate> </table> </FooterTemplate> </asp:DataList>
To wrap things up, it's easy to map what you know about Web Forms to what you're learning about Linq in VB. The LinqDataSource connects your underlying Linq to SQL DataContext, or any generalized Linq query, to the rest of your Web Form. You can create totally custom queries in the LinqDataSource.Selecting event and pass that to the control via e.Result. And then you can get at any field or property in your Linq query using classic Eval("MYFIELD") data binding expressions.
What do you think? What additions would you like to see?
If you want more info now, ScottGu put together an awesome series of Linq to SQL posts for the Web, and he included VB sample code. Another great portal for learning and How To content is www.asp.net.
Best,
Paul
----------------------------------
Paul Yuknewicz Lead Program Manager Microsoft Visual Studio http://msdn.com/vbasic/
PingBack from http://geeklectures.info/2007/12/27/linq-for-the-web-using-vb-by-paul-yuknewicz/
How can we do something like this? Do we have to specify all the fields for both tables? Line 82 throws an exception?
Dim iiresult = From ii In db.InventoryItems, il In db.InventoryLogs Select ii, il
GridView2.DataSource = iiresult
GridView2.DataBind()
Server Error in '/' Application.
--------------------------------------------------------------------------------
The data source for GridView with id 'GridView2' did not have any properties or attributes from which to generate columns. Ensure that your data source has content.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Web.HttpException: The data source for GridView with id 'GridView2' did not have any properties or attributes from which to generate columns. Ensure that your data source has content.
Source Error:
Line 80:
Line 81: GridView2.DataSource = iiresult
Line 82: GridView2.DataBind()
Line 83:
Line 84:
Pingback from http://oakleafblog.blogspot.com/2007/12/linq-and-entity-framework-posts-for_24.html
>>How can we do something like this? Do we have to specify all the fields for both tables?
Yes, given my assumption of your data, ii and il are both lists and you need to set a single list as the DataSource to auto populate the columns. You could either specify all the columns in your query -- which creates a new flast list from an anonymous query type:
Select InventoryID = ii.InventoryID, LogId = il.LogID
or you could change the GridView columns into template columns and drill into the ii and il sub properties through <%# Eval("property.subproperty") %> statements in the item templates. Either way, you're doing some extra work to drill into properties in these multiple object graphs.
I'll ask around if there is a way to do this completely dynamically. I don't think there is a way currently with multiple tables/lists or object graphs. ScottGu suggests a similar approach in his blog comment responses.
Thanks,
An example of how to use LING to SQL in Multi-Tier would be very useful with say frontends in WebForm & WPF (with Web Service). I have read on many sites that LINQ to SQL is more useful in a 2-Tier app
Where do I find your promised link to the Northwind database download beneath your article ?
Thanks !
Excuse..........I believe it sits in the VBWebLINQSample-Complete.zip file
Regards