Title: The Adventure of LINQ Language Integrated Query
1The Adventure of LINQ(Language Integrated Query)
- Presented by
- Richard Broida
- Senior Architect
2Visual Studio 2005 Team System Tour
- Coming to Cleveland!
- February 22, 2006
- 900 AM 430 PM
- Right Here
- Free!
- Sign Up
- http//msevents.microsoft.com
- Event Code 1032288761
3Agenda
- LINQs Quest Make Queries Easier
- Hello, LINQ
- LINQ Internals
- DLINQ Using LINQ with Relational Data
- XLINQ Using LINQ with XML
- Resources on the Web
- Q A
4LINQs Quest Make Queries Easier
- Make query syntax part of the programming
language - Use the same query syntax for all types of data
- Relational, hierarchical, or flat
- Persistent or in-memory
- Make query input and output always type-safe
- Provide full tool support in IDE
5Back to the Future
- In 1991 FoxPro 2.0 had SQL SELECT, INSERT, UPDATE
and DELETE integrated into the language - No command object just write the query
- SQL statements could incorporate FoxPro
expressions and functions and/or user-defined
functions at will - Database data types were exactly the same as
language data types - SELECT produced a table that knew its column
names, data types and sizes
6.NET 2.0 Still Hasnt Caught Up with FoxPro 2.0
- SQL isnt part of your .NET language
- No compile-time type checking
- No IntelliSense
- Set-based approach of SQL is foreign to
procedural languages - Queries return typeless DataReaders and
DataTables - Column names arent part of the object
- Must identify by string or numeric index
- Must cast column value to correct data type and
size - Persisting objects to tables requires application
code - Write it manually, or
- Use code generator, or
- Use runtime O/R mapper
7What You Are -gt How You Query
- Collections
- Index Looping
- IEnumerable (For Each looping)
- Sort() and Find() methods
- Relational Data
- SQL
- XML
- XPATH
- XQUERY
- Active Directory
- LDAP
- ADSI
- Etc
8The Realms of LINQ
- System.Query namespace
- Provides default implementation of standard query
operators for IEnumerable and IEnumerableltTgt - Uses in-memory iterators
- System.Data.DLinq namespace
- Translates standard query operators into SQL that
executes on database server - System.Data.XLinq namespace
- A new XML API that supports LINQ as alternative
to XPath and XQuery - Third Party Extensions
- Further specialization of standard query
operators - Creation of new query operators
9Hello, LINQ
10History of LINQ
- Conceived by Anders Hejlsberg, creator of C
- September 2005 First technology preview for C
2.0 (Beta 2) released at PDC - November 2005 Update of PDC CTP for C 2.0 RTM
- January 2006 First technology preview for
Visual Basic 8.0 RTM - ??? Future CTPs, Betas and RTM
11Getting LINQ
- Download latest version from
- http//msdn.microsoft.com/netframework/future/linq
- As of 2/14/2005, the latest versions are
- C November 2005 Technology Preview
- VB January 2006 Technology Preview
- Both require
- WinXP SP2
- RTM of VS.NET 2005 (or C/VB Express)
- RTM of SQL Server 2005 (or Express)
- Dont install on a working box! Use a VM if
possible. - C IDE integration doesnt install by default.
See instructions in ReadMe.htm - Make sure Options - Project Templates are set to
default locations under My Documents
12Creating a LINQ Project in Visual Studio
- With the current CTPs, you can only use LINQ in
Visual Studio if you create a LINQ Project - Behind the scenes, this causes VS to use a
special LINQ-enabled compiler
13Hello, LINQ in C
- using System.Query
- int numbers 5, 4, 1, 3, 9, 8, 6, 7, 2, 0
-
- var lowNums
- from n in numbers
- where n lt 5
- select n
- foreach (var num in lowNums )
- Console.WriteLine(num)
-
14Hello, LINQ in VB
- Option Strict On
- Imports System.Query
- Dim numbers as Integer() _
- 5, 4, 1, 3, 9, 8, 6, 7, 2, 0
- Dim lowNums _
- Select n _
- From n In numbers _
- Where n lt 5
- For Each num In lowNums
- Console.WriteLine(num)
- Next
15In C SELECT and FROM Reversed They Are
- In C 3.0, the IDE still doesnt do background
compilation, so it has to parse code line-by-line - Putting SELECT before FROM would prevent
IntelliSense from knowing what can be SELECTed - Visual Basic can put SELECT first because its IDE
supports background compilation
16Standard Query Operators
- These work similarly to their SQL counterparts
- Select
- Where
- OrderBy/ThenBy
- OrderByDescending/ThenByDescending
- GroupBy
- Count
- Sum/Min/Max/Average
17Positional Query Operators
- First/FirstOrDefault
- Returns first element satisfying a predicate
- ElementAt
- Returns element at a numeric position
- Take/Skip
- Returns all elements before/after a numeric
position - TakeWhile/SkipUntil
- Returns elements while predicate satisfied
- Reverse
- Returns elements in reverse order
- Range
- Returns subset of elements in a range
18Set Based Query Operators
- Combine two sets of elements
- Union
- Returns all distinct elements in both sets
- Intersection
- Returns only elements belonging to both sets
- Except
- Returns elements in Set A but not in Set B
- Repeat
- Returns multiple copies of a set of elements
- Distinct
- Removes duplicate elements
19Projection Creating New Types To Hold Query
Results
- The result of the query can be an IEnumerableltTgt
of a new type custom-created to hold the data - int digits 0, 1, 2
- string stooges Moe, Larry, Curly
- var v from n in digits
- select new Index n, Name stoogesn
- foreach ( var stooge in v )
- Console.WriteLine( Stooge 0 is 1,
- stooge.Index, stooge.Name )
20Projection That Creates a Nested 1-Many
Collection
- A query can be nested inside another query to
produce a 1-Many Collection -
- var q from c in db.Customers where c.City
"London" select new c.CompanyName, c.Phone,
OrderDates ( from o in c.Orders select
o.OrderDate) .Take(5) - foreach( var c in q )
- Console.WriteLine( c.CompanyName )
- foreach( od in c.OrderDates )
- Console.WriteLine( od )
-
21What Can You Query with LINQ?
- Any object that implements IEnumerableltTgt
- Single-dimension arrays
- ListltTgt
- Etc
- Any object that implements non-generic
IEnumerable - Use OfTypeltTgt extension method to convert it to
IEnumerableltTgt - ArrayList objectList GetAnArrayList()
- IEnumerableltintgt ints objectList.OfTypeltintgt
- IEnumerableltintgt smallInts ints.Whereltintgt(
- i gt i lt 5 )
22LINQ Queries Are Lazy
- Assigning a query to an IEnumerableltTgt variable
doesnt execute the query - When user iterates over members of the
collection, each query operator executes as many
times as needed to retrieve the next element - Hence the data can change while elements are
still being retrieved - Use .ToListltTgt or .ToArrayltTgt to force iteration
over the entire query in one statement - Creates a snapshot copy of the original data
23Modifying a Query Before Execution
- Since execution is deferred, query can be
modified any number of times before iteration - var v from city in cities
- where city.Name.Length gt 3
- select city
- if (orderAscending)
- v from city in v
- orderBy city.Name
- select city
- foreach (city in v)
24LINQ Internals
25LINQ Internals
- LINQ is built from language features that are
useful in their own right - .NET 2.0 Features
- Generics
- Anonymous Methods
- Iterators
- Static Classes
- SQL Data Types
- New Language Features
- Compile-Time Type Inference
- Object and Array Initializers
- Anonymous Types
- Extension Methods
- Lambda Expressions
- Expression Trees
26LINQ Is a Compiler Technology
- LINQ depends on compiler and library technology,
not CLR innovations - The current CTPs run on the standard .NET 2.0 CLR
- At least theoretically LINQ could RTM before the
.NET 3.0 CLR - Each compiler implements LINQ differently, if at
all
27Compile-Time Type Inference
- No need to declare a variables type
- Compiler infers it from the object assigned to it
- Because the type inference happens at compile
time, this is still 100 type-safe -
- C
- var v Hello // v is type string
- v 42 // ERROR, type mismatch
- var w // ERROR, what type is it?
- VB
- dim v Hello v is type String
- v 123 ERROR, type mismatch
- dim w ERROR, even if Option Strict Off
-
- VB late binding requires Option Strict Off and
Object variable - dim o as Object World
- o 123 no error
28Object Initializers
- Allow creation of an object and initialization of
its public data in one line of code, without
calling a multi-argument constructor - Used to create objects in lambda expressions and
expression trees - C
- Class Person
- public string Name
- public int Age
-
- Person p new Person Name Ralph, Age 23
- VB
- Dim p New Person .Name Ralph, .Age 23
29Array Initializers
- Person people
-
- new Person Name Bill, Age 42,
- new Person Name Namita, Age 29,
- new Person Name Juan, Age 47,
- new Person Name Alice, Age 31,
- new Person Name Al, Age 22,
30Anonymous Types
- Compiler creates a type that matches the
arguments used in an initializer - Type has only public fields, no methods
- C
- var p new Name Ralph, Age 23
- VB
- Dim p New .Name Ralph, .Age 23
31Anonymous Types and Type Safety
- Though unnamed in the source code, the type is
fully defined in the IL, so there is no loss of
type safety or IDE tool support - However, the type cannot be referenced outside
its assembly - var fred new Name "Fred", Age 23
- var barney new Name "Barney", Age 24
- fred barney // OK, types are the same
- fred 42 // ERROR, type mismatch
32Projection Creating Anonymous Types Out of Other
Types
- var customer
- Name Fred Blogs, Zip 44125
- var product
- Name Widget, Price 16.99
- var order customer.Name,
- Product product.Name,
- product.Price,
- Quantity 12
- Console.WriteLine(
- Customer 0, Product 1, Total 2,
- order.Name, order.Product,
- order.Price x order.Quantity )
33Extension Methods
- The Problem How to add a method to a type you
dont control and cant subtype? - Example How to add Standard Query Operators to
IEnumerableltTgt, without deriving a new interface? - Solution Extension methods arent really members
of the target type, but the syntax makes them
look that way - Compile-time type safety is preserved
34Creating Extension Methods
- Define a Static Class
- Define a static method whose first argument is an
object of type T - System.Runtime.CompilerServices.Extension
attribute on first parameter tells CLR the method
is an Extension - C binds the attribute to keyword this
- Create a T object, and call the method as if it
were a member of the object - When the compiler fails to find the method among
Ts members, it searches for an extension method
in scope with matching name and signature
35Extension Method in C
- public static class StringExtender
-
- const string vowels "aeiouy"
- // keyword this indicates the
CompilerServices.ExtensionAttribute - public static string NoVowels( this string s )
- StringBuilder sb new StringBuilder()
- foreach ( char c in s )
- if ( -1 vowels.IndexOf(c) )
- sb.Append(c)
- return sb.ToString()
-
-
-
- static void Main()
- string s "abcde"
- // string appears to have a NoVowels() method
- Console.WriteLine( s.NoVowels() ) // outputs
bcd -
36Extension Method in VB
- ltSystem.Runtime.CompilerServices.Extension()gt _
- Public Module StringExtender
- Const vowels As String "aeiouy"
- ltSystem.Runtime.CompilerServices.Extension()gt _
- Public Function NoVowels(ByVal Me As String)
As String - Dim sb As New System.Text.StringBuilder()
- For Each Dim c As Char In Me
- If -1 vowels.IndexOf(c) Then
- sb.Append(c)
- End If
- Next
- Return sb.ToString()
- End Function
- End Module
37LINQ Implements Standard Query Operators As
Extension Methods
- namespace System.Query
- public static class Sequence
-
- public static IEnumerableltTgt WhereltTgt(
- this IEnumerableltTgt source,
- FuncltT, boolgt predicate)
-
- foreach (T item in source)
- if (predicate(item))
- yield return item
-
-
38Replacing LINQ Extension Methods
- Extension Methods have lower priority of
resolution than type members - So if a type has a member with same signature as
a LINQ extension method, the types member will
be called, and there is no ambiguity - class MyList IEnumerableltintgt
- public IEnumerableltintgt Where(
- Funcltint,boolgt filter)
- // LINQ queries on MyList objects will call
this - // instead of Sequence.Where()
-
- This is how DLINQ and XLINQ replace the default
LINQ implementations of the Standard Query
Operators
39Lambda Expressions
- Extends .NET 2.0 Anonymous Methods with even
simpler syntax - Like anonymous methods, theres no need to call
an existing method on a type - Like anonymous methods, local variables stay in
scope when the lambda expression executes - No need for delegate keyword
- No need to restate the parameter types
- Syntax
- parameters gt expression
- As of February 2006, C supports lambda
expressions, but VB does not and may never
40Comparing Delegates, Anonymous Methods and Lambda
Expressions
- class LotsOfUppers
- delegate string MyDelegate(string s)
- private static string MyFunc(string s) return
s.ToUpper() - static void Main()
- Console.WriteLine( MyFunc(Calling a
Function) - MyDelegate del
- del new MyDelegate( MyFunc )
- Console.WriteLine( del(Calling a .NET 1.0
Delegate") ) - del delegate( string s ) return
s.ToUpper() - Console.WriteLine( del(Calling a .NET 2.0
Anonymous Method") ) - del s gt s.ToUpper()
- Console.WriteLine( del(Calling a .NET 3.0
Lambda Expression") )
41Parameters to Lambda Expressions
- Implicitly typed parameter
- Parentheses optional for single implicitly typed
parameter - x gt x 1
- (x) gt x 1
- Explicitly typed parameter
- (int x) gt x 1
- int x gt x 1 //ERROR, no parens
- Implicitly typed, multiple parameters
- (x, y) gt x y
- x, y gt x y //ERROR, no parens
- No parameters
- Not supported in current CTP
- () gt Console.WriteLine()
42Lambda Body Can Be Single Expression or Statement
Block
- Expression body
- x gt x 1
- Statement block body
- x gt return x 1
- Statement body can have arbitrarily many lines
- As of February 2006, the current CTP does not
support statement bodies in lambdas. You must use
.NET 2.0 anonymous methods instead. - Only expression body lambdas can compile into
expression trees
43Hello, LINQ With Explicit Lamba Expressions
- using System.Query
- int numbers 5, 4, 1, 3, 9, 8, 6, 7, 2, 0
-
- var lowNums
- numbers
- .Where(n gt n lt 5)
- .Select (n gt n)
44Expression Trees
- When compiled as a delegate, lambda expression
produces IL code just like a classic delegate or
anonymous method - In that case, only benefit is simpler syntax
- Or, lambda expression can be compiled to an
expression tree - An efficient in-memory data structure that makes
the structure of the expression transparent and
explicit - This allows the expression to be evaluated,
copied and modified without using reflection - DLINK uses expression trees to construct SQL
statements that can execute on database server
45Expression Tree Example
- delegate bool MyDelegate(int i)
-
- MyDelegate il n gt n lt 5
- Console.WriteLine( il(7)) // OK, il is an
executable delegate -
- ExpressionltMyDelegategt ex n gt n gt 4
- Console.WriteLine( ex(7) ) // ERROR, ex not
executable - BinaryExpression body (BinaryExpression)ex.Body
- ParameterExpression left (ParameterExpression)
body.Left - ConstantExpression right (ConstantExpression)b
ody.Right - Console.WriteLine( "BODY 0, LEFT 1, RIGHT
2", - body, left, right )
- // BODY GT(n, 4), LEFT n, RIGHT 4
46Types of Expression Tree Nodes
- BinaryExpression
- ConstantExpression
- FuncletExpression
- InvocationExpression
- LambdaExpression
- MemberExpression
- MethodCallExpression
- NAryExpression
- NewArrayExpression
- NewExpression
- ParameterExpression
- TernaryExpression
- TypeBinaryExpression
- UnaryExpression
47DLINQ
48DLINQ Using LINQ with Relational Databases
- DLINQ is the next version of ADO.NET
- DLINQ supports class-first design
- Write classes
- Use attributes to map classes to tables and
properties to columns - DLINQ supports both data retrieval and updates
- Currently DLINQ only supports SQL Server 2005
49How DLINQ Works
- DLINQ does not execute queries the database
server does - DLINQ queries are compiled to expression trees
rather than IL - At runtime DLINQ parses the expression trees,
constructs equivalent T-SQL statements, and sends
them to the server - Statements are not executed as SQL/CLR
- Thus .NET expressions that cannot translate to
T-SQL are disallowed - Cant call .NET functions with no T-SQL equivalent
50Attribute-Based DLINQ Mapping
- Table(NameCustomers)
- class Customer
-
- Column(IDtrue)
- public string CustomerID
-
- Column
- public string City
- Column
- public string PostalCode
51The DataContext
- Like an xxxConnection in ADO.NET, the DataContext
class binds table objects to a database
connection - By making the tables members of a DataContext
subclass, the binding takes place transparently - class NorthWind DataContext
-
- public TableltCustomergt Customers
- public TableltOrdergt Orders
- public NorthWind( string connection )
- base( connection )
52Hello, DLINQ
- NorthWind db new NorthWind(
- connectonString )
- var londonCustomers
- from c in db.Customers
- where c.City London
- select c
-
- foreach ( Customer c in londonCustomers )
- Console.WriteLine( c.ContactName )
53When Does the Query Go to the Database?
- In the previous example, the query goes to the
database at the first iteration of the foreach
loop - All the rows come back, so subsequent iterations
retrieve the data from memory - If the same query is iterated in a second foreach
loop, the query will go to the database a second
time - To prevent this, copy the result of the query
with ToListltTgt() or ToArrayltTgt() and iterate over
the copy
54Declaring Parent-Child Relationship
- Table(Name"Customers")
- public class Customer
-
- Column(Idtrue) public string
CustomerID ... - private EntitySetltOrdergt _Orders
- Association(Storage"_Orders",
OtherKey"CustomerID") - public EntitySetltOrdergt Orders
- get return this._Orders set
this._Orders.Assign(value)
55Declaring Child-Parent Relationship
- Table(Name"Orders")
- public class Order
-
- Column(Idtrue)
- public int OrderID
- Column
- public string CustomerID
- private EntityRefltCustomergt _Customer
-
- Association(Storage"_Customer",
ThisKey"CustomerID") - public Customer Customer
- get return this._Customer.Entity set
this._Customer.Entity value -
-
56Attribute-Based Joins
- // parent to children
- var q
- from c in db.Customers, o in c.Orders
- where c.City "London
- select new c, o
- // child to parent
- var q
- from o in db.Orders
- where o.Customer.City "London
- select new c o.Customer, o
57Controlling How Much Joined Data To Retrieve
- By default, a DLINQ query only retrieves what is
requested in Select clause. - Use .Including() method to retrieve data for
related objects at same time - var q (
- from c in db.Customers
- where c.City London
- select c)
- .Including(c gt c.Orders)
58Executing Part of a Query on Database Server and
Part Locally
- .ToSequence() tells DLINK to run the query on the
database server up to that point, then run the
rest of the query locally - var q from c in db.Customers where c.City
London select new c.ContactName, c.Phone - // cant call these functions on database server
- var q2
- from c in q.ToSequence()
- select new MyType Name DoNameProcessing(c.C
ontactName), - Phone DoPhoneProcessing(c.Phone)
59Updating the Database
- DataContext tracks changes to Tables in memory.
- SubmitChanges() submits them to database.
- Northwind db new Northwind("northwnd.mdf")
- var cust db.Customers.First(c gt c.ID
ACKE") - cust.ContactName "New Contact"
- Order order cust.Orders0
- db.Orders.Remove(order)
- order new Order OrderId 12345
cust.Orders.Add(order) - db.SubmitChanges()
60The SQLMetal Utility
- Command line utility provided with current CTP to
automate creation of annotated entity classes to
match a database schema - SqlMetal /server.\SQLExpress /databaseNorthwin
d - /delayfetch
- /pluralize
- /namespacenwind
- /codeNorthwind.cs
61XLINQ
62XLINQ Using LINQ with XML
- Intended to be a complete XML API with all
features of WC3 DOM - Simpler and more efficient
- Integrates XML with other data sources supported
by LINQ - Still supports traditional DOM-style programming
63XLINQ (XElement) vs. DOM (XmlElement)
- XElement neednt be part of a document object
- An XDocument can be created if needed, but
XElements can exist without it - XElement.Name property doesnt include a
namespace prefixes - XLINQ resolves namespaces and prefixes at
serialization time - Leaf elements can be cast directly into data
- int age (int)xAge // XLINQ
- int age (int)xAge.InnerText //DOM
- XElement.ToString() outputs the underlying XML
- doh!
64Creating XML in Memory with WC3 DOM
-
- XmlDocument doc new XmlDocument()XmlElement
name doc.CreateElement("name")name.InnerText
Fred Blogs"XmlElement phone1
doc.CreateElement("phone")phone1.SetAttribute("t
ype", "home")phone1.InnerText "206-555-0144"
XmlElement postal doc.CreateElement("pos
tal")postal.InnerText "68042"XmlElement
address doc.CreateElement("address")address.Ap
pendChild(postal)XmlElement contact
doc.CreateElement("contact")contact.AppendChild(
name)contact.AppendChild(phone1)contact.Append
Child(address)XmlElement contacts
doc.CreateElement("contacts")contacts.AppendChil
d(contact)doc.AppendChild(contacts)
65Creating XML in Memory with XLINQ in C
- XElement contacts new XElement("contacts", new
XElement("contact", new XElement("name", Fred
Blogs"), new XElement("phone", "206-555-0144",
new XAttribute("type", "home")), new
XElement("phone", "425-555-0145", new
XAttribute("type", "work")), new
XElement("address", new XElement("street1",
"123 Main St"), new XElement("city", "Mercer
Island"), new XElement("state", "WA"), new
XElement("postal", "68042") ) )) - This is accomplished thanks to the XElement
constructor - public XElement(XName name, params object
contents)
66Traditional XML Programming with XLINQ
- Populate from a string using XElement.Parse(), or
from a file, XmlReader or TextReader using
XElement.Load() - XDocument doc XElement.Load(_at_"c\myContactList.
xml") - Traverse the object hierarchy and manipulate
contents - XElement contacts doc.Element(root).Element(
contacts) - foreach ( XElement contact in
contacts.Content() ) -
- if ( Joe (string)contact.Element(name)
-
- contact.Element(zip").ReplaceContent(44125")
-
-
-
67LINQ Query on XLINQ Object
- XDocument doc XDocument.Load("customers.xml")
- var query
- from c in
- doc.Element("Root")
- .Elements("Customers")
- where
- c.Element("FullAddress")
- .Element("Country")
- .Value "Germany"
- select c
-
- foreach (XElement result in query)
- Console.WriteLine(result)
68Casting and Filtering on an Attribute
- string xml "ltorder gt"
- "ltitem price'150'gtMotorlt/item
gt" - "ltitem price'50'gtCablelt/itemgt
" - "ltitem price'50'gtModemlt/itemgt
" - "ltitem price'250'gtMonitorlt/it
emgt" - "ltitem price'10'gtMouselt/itemgt
" - "lt/ordergt"
- XElement order XElement.Parse(xml)
- var query
- from
- i in order.Elements("item")
- where
- (int)i.Attribute("price") gt 100
- select i
- foreach(var result in query)
- Console.WriteLine("Expensive Item 0 costs
1", - (string)result,
- (string)result.Attribute("pr
ice"))
69Transforms with XLINQ
- XDocument doc XDocument.Load("customers.xml")
-
- var header new
- new XElement("th", "customer id"),
- new XElement("th", "contact name")
- var rows
- from
- customer in doc.Descendants("Customers")
- where
- (decimal)customer.Element(salesYTD) gt 500,000
- select
- new XElement("tr",
- new XElement("td", (string)customer.Attribute("C
ustomerID")), - new XElement("td", (string)customer.Element("Con
tact"))) - XElement html new XElement("html",
- new XElement("table", header, rows))
- Console.Write(html)
70XLINQ Enhancement for VB Only XML Literals
- VB can create XElements in memory with XElement
constructors, same as in C - Dim contacts As XElement _ New
XElement("contacts", _ New
XElement("contact", _ New
XElement("name", Fred Blogs"), _ New
XElement("phone", "206-555-0144", _
New XAttribute("type", "home")), _
New XElement("phone", "425-555-0145", _
New XAttribute("type", "work")), _
New XElement("address", _ New
XElement("street1", "123 Main St"), _
New XElement("city", "Mercer Island"), _
New XElement("state", "WA"), _
New XElement("postal", "98040"))))
71Creating an XElement from an XML Literal
- Wouldnt you rather do this?
- Dim contacts As XElement _ ltcontactsgt
ltcontactgt ltnamegtFred
Blogslt/namegt ltphone
type"home"gt206-555-0144lt/phonegt
ltphone type"work"gt425-555-0145lt/phonegt
ltaddressgt ltstreet1gt123 Main
Stlt/street1gt ltcitygtMercer
Islandlt/citygt ltstategtWAlt/stategt
ltpostalgt98040lt/postalgt
lt/addressgt lt/contactgt
lt/contactsgt - Compiler converts this to same code as previous
slide - No need for line continuation characters within
the XML
72VB XML Literals Can Contain Expressions Evaluated
at Runtim
- Element Value from Variable
- Dim name As XElement
- ltnamegtltsomeVariablegtlt/namegt
-
- Element Value from Function Call
- Dim name As XElement
- ltnamegtltSomeFunction()gtlt/namegt
-
- Attribute Value from Variable
- Dim phone as XElement
- ltphone type(someVariable)gt234-5678lt/phonegt
- Element Name from Variable
- Dim contact as XElement
- ltcontactgt
- lt(someVariable)gtFoolt/gt
- lt/contactgt
73Embedding XLINQ Query Inside XML Literal
- Dim contacts as XElement _
- ltcontactsgt
- lt
- _Select _
- ltcontactgt
- ltnamegtltCStr(c.name(0))gtlt/namegt
- ltc.phone gt
- ltaddressgtltc.addressgtlt/addressgt
ltcontact/gt - From c In contacts
- gt
- lt/contactsgt
74XLINQ Enhancement for VB Only Late Bound XML
- VB can apply three XPath-style navigational
operators to an XElement - Child axis operator .
- Descendants axis operator
- Attribute axis operator _at_
- This makes the syntax simpler than the
index-based XElement methods - However, VB applies these operators at runtime
using late binding, so their use is not type-safe
75Late Bound XML Example
- For Each Dim phone In contact.phone
- Console.WriteLine(CStr(phone._at_type))
- Next
- Console.WriteLine(CStr(contacts...city(0)))
- which is equivalent to
- For Each Dim phone In Contact.Element("phone")
- Console.WriteLine(CStr(phone.Attribute("type"))
- Next
- Console.WriteLine( _
- CStr(ElementAt(contact.Descendants("city"),0)))
76Schema-Aware XLINQ?
- Current XLINQ CTPs are unaware of XML structure
at compile time - Nodes must be located at run time using indexes,
and values must be cast to correct data type - string zip (string)name.Element(zip)
- Microsoft is investigating possibility of using
XML Schemas at compile time/design time to
construct strongly typed XML objects -
- string zip name.zip
77The Adventure Continues!
78LINQ Resources on the Web
- LINQ Official Site
- http//msdn.microsoft.com/netframework/future/linq
- Barry Gervins LINQ Resources
- http//objectsharp.com/blogs/barry/archive/2005/09
/13/3395.aspx
79Q A