Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Relational algebra wikipedia , lookup
Microsoft Jet Database Engine wikipedia , lookup
Open Database Connectivity wikipedia , lookup
Entity–attribute–value model wikipedia , lookup
Microsoft SQL Server wikipedia , lookup
Clusterpoint wikipedia , lookup
Database model wikipedia , lookup
The Adventure of LINQ (Language Integrated Query) Presented by: Richard Broida Senior Architect Bennett Adelson Visual Studio 2005 Team System Tour • Coming to Cleveland! – – – – – February 22, 2006 9:00 AM – 4:30 PM Right Here Free! Sign Up: • http://msevents.microsoft.com • Event Code: 1032288761 Bennett Adelson Agenda • • • • • • • LINQ’s 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 Bennett Adelson LINQ’s 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 Bennett Adelson Back 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 userdefined 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 Bennett Adelson .NET 2.0 Still Hasn’t Caught Up with FoxPro 2.0 • SQL isn’t 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 aren’t 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 Bennett Adelson What You Are -> 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 … Bennett Adelson The Realms of LINQ • System.Query namespace – Provides default implementation of standard query operators for IEnumerable and IEnumerable<T> – 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 Bennett Adelson Hello, LINQ Bennett Adelson History 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 Bennett Adelson Getting 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) – Don’t install on a working box! Use a VM if possible. • C# IDE integration doesn’t install by default. See instructions in ReadMe.htm – Make sure Options - Project Templates are set to default locations under My Documents Bennett Adelson Creating 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 Bennett Adelson Hello, 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 < 5 select n; foreach (var num in lowNums ) { Console.WriteLine(num); } Bennett Adelson Hello, 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 < 5 For Each num In lowNums Console.WriteLine(num) Next Bennett Adelson In C# SELECT and FROM Reversed They Are • In C# 3.0, the IDE still doesn’t 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 Bennett Adelson Standard Query Operators • These work similarly to their SQL counterparts – – – – – – – Select Where OrderBy/ThenBy OrderByDescending/ThenByDescending GroupBy Count Sum/Min/Max/Average Bennett Adelson Positional 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 Bennett Adelson Set 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 Bennett Adelson Projection: Creating New Types To Hold Query Results • The result of the query can be an IEnumerable<T> 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 = stooges[n] }; foreach ( var stooge in v ) Console.WriteLine( “Stooge {0} is {1}”, stooge.Index, stooge.Name ) Bennett Adelson Projection That Creates a Nested 1-Many Collection • A query can be nested inside another query to produce a 1Many 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 ) } Bennett Adelson What Can You Query with LINQ? • Any object that implements IEnumerable<T> – Single-dimension arrays – List<T> – Etc • Any object that implements non-generic IEnumerable – Use OfType<T> extension method to convert it to IEnumerable<T> ArrayList objectList = GetAnArrayList(); IEnumerable<int> ints = objectList.OfType<int>; IEnumerable<int> smallInts = = ints.Where<int>( i => i < 5 ); Bennett Adelson LINQ Queries Are Lazy • Assigning a query to an IEnumerable<T> variable doesn’t 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 .ToList<T> or .ToArray<T> to force iteration over the entire query in one statement – Creates a snapshot copy of the original data Bennett Adelson Modifying 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 > 3 select city if (orderAscending) v = from city in v orderBy city.Name select city foreach (city in v) { … Bennett Adelson LINQ Internals Bennett Adelson LINQ 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 Bennett Adelson LINQ 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 Bennett Adelson Compile-Time Type Inference • No need to declare a variable’s type • C# • VB • VB late binding requires Option Strict Off and Object variable dim o as Object = “World” o = 123 ‘ no error – Compiler infers it from the object assigned to it – Because the type inference happens at compile time, this is still 100% typesafe var v = “Hello”; v = 42; var w; // v is type string // ERROR, type mismatch // ERROR, what type is it? dim v = “Hello” v = 123 dim w ‘ v is type String ‘ ERROR, type mismatch ‘ ERROR, even if Option Strict Off Bennett Adelson Object 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 } Bennett Adelson Array Initializers Person[] people = { new new new new new Person Person Person Person Person { { { { { Name Name Name Name Name = = = = = “Bill”, Age = 42}, “Namita”, Age = 29}, “Juan”, Age = 47}, “Alice”, Age = 31}, “Al”, Age = 22}, }; Bennett Adelson Anonymous 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 } Bennett Adelson Anonymous 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 Bennett Adelson Projection: 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 ); Bennett Adelson Extension Methods • The Problem: How to add a method to a type you don’t control and can’t subtype? – Example: How to add Standard Query Operators to IEnumerable<T>, without deriving a new interface? • Solution: Extension methods aren’t really members of the target type, but the syntax makes them look that way – Compile-time type safety is preserved Bennett Adelson Creating 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 T’s members, it searches for an extension method in scope with matching name and signature Bennett Adelson Extension 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” } Bennett Adelson Extension Method in VB <System.Runtime.CompilerServices.Extension()> _ Public Module StringExtender Const vowels As String = "aeiouy" <System.Runtime.CompilerServices.Extension()> _ 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 Bennett Adelson LINQ Implements Standard Query Operators As Extension Methods namespace System.Query { } } public static class Sequence { … public static IEnumerable<T> Where<T>( this IEnumerable<T> source, Func<T, bool> predicate) { foreach (T item in source) if (predicate(item)) yield return item; } Bennett Adelson Replacing 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 type’s member will be called, and there is no ambiguity class MyList : IEnumerable<int> { public IEnumerable<int> Where( Func<int,bool> 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 Bennett Adelson Lambda Expressions • Extends .NET 2.0 Anonymous Methods with even simpler syntax – Like anonymous methods, there’s 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 => expression • As of February 2006, C# supports lambda expressions, but VB does not and may never Bennett Adelson Comparing 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 => s.ToUpper() ; Console.WriteLine( del(“Calling a .NET 3.0 Lambda Expression") ); Bennett Adelson Parameters to Lambda Expressions • Implicitly typed parameter – Parentheses optional for single implicitly typed parameter x => x + 1 (x) => x + 1 • Explicitly typed parameter (int x) => x + 1 int x => x + 1 //ERROR, no parens • Implicitly typed, multiple parameters (x, y) => x * y x, y => x * y //ERROR, no parens • No parameters – Not supported in current CTP () => Console.WriteLine() Bennett Adelson Lambda Body Can Be Single Expression or Statement Block • Expression body x => x + 1 • Statement block body x => { 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 Bennett Adelson Hello, 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 => n < 5) .Select (n => n); Bennett Adelson Expression 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 Bennett Adelson Expression Tree Example delegate bool MyDelegate(int i); … MyDelegate il = n => n < 5; Console.WriteLine( il(7)); // OK, il is an executable delegate Expression<MyDelegate> ex = n => n > 4; Console.WriteLine( ex(7) ); // ERROR, ex not executable BinaryExpression body = (BinaryExpression)ex.Body; ParameterExpression left = (ParameterExpression)body.Left; ConstantExpression right = (ConstantExpression)body.Right; Console.WriteLine( "BODY: {0}, LEFT: {1}, RIGHT: {2}", body, left, right ); // BODY: GT(n, 4), LEFT: n, RIGHT: 4 Bennett Adelson Types of Expression Tree Nodes • • • • • • • • • • • • • • BinaryExpression ConstantExpression FuncletExpression InvocationExpression LambdaExpression MemberExpression MethodCallExpression NAryExpression NewArrayExpression NewExpression ParameterExpression TernaryExpression TypeBinaryExpression UnaryExpression Bennett Adelson DLINQ Bennett Adelson DLINQ: 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 Bennett Adelson How 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 • Can’t call .NET functions with no T-SQL equivalent Bennett Adelson Attribute-Based DLINQ Mapping [Table(Name=“Customers”)] class Customer { [Column(ID=true)] public string CustomerID; [Column] public string City; [Column] public string PostalCode; } Bennett Adelson The 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 Table<Customer> Customers; public Table<Order> Orders; public NorthWind( string connection ) : base( connection ) {} } Bennett Adelson Hello, 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 ); } Bennett Adelson When 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 ToList<T>() or ToArray<T>() and iterate over the copy Bennett Adelson Declaring Parent-Child Relationship [Table(Name="Customers")] public class Customer { [Column(Id=true)] public string CustomerID; ... private EntitySet<Order> _Orders; } [Association(Storage="_Orders", OtherKey="CustomerID")] public EntitySet<Order> Orders { get { return this._Orders; } set { this._Orders.Assign(value); } } Bennett Adelson Declaring Child-Parent Relationship [Table(Name="Orders")] public class Order { [Column(Id=true)] public int OrderID; [Column] public string CustomerID; private EntityRef<Customer> _Customer; } [Association(Storage="_Customer", ThisKey="CustomerID")] public Customer Customer { get { return this._Customer.Entity; } set { this._Customer.Entity = value; } } Bennett Adelson Attribute-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 }; Bennett Adelson Controlling 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 => c.Orders); Bennett Adelson Executing 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 }; // can’t call these functions on database server var q2 = from c in q.ToSequence() select new MyType { Name = DoNameProcessing(c.ContactName), Phone = DoPhoneProcessing(c.Phone) }; Bennett Adelson Updating 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 => c.ID == “ACKE"); cust.ContactName = "New Contact"; Order order = cust.Orders[0]; db.Orders.Remove(order); order = new Order { OrderId = 12345 }; cust.Orders.Add(order); db.SubmitChanges(); Bennett Adelson The SQLMetal Utility • Command line utility provided with current CTP to automate creation of annotated entity classes to match a database schema SqlMetal /server:.\SQLExpress /database:Northwind /delayfetch /pluralize /namespace:nwind /code:Northwind.cs Bennett Adelson XLINQ Bennett Adelson XLINQ: 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 Bennett Adelson XLINQ (XElement) vs. DOM (XmlElement) • XElement needn’t be part of a “document” object – An XDocument can be created if needed, but XElements can exist without it • XElement.Name property doesn’t 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! Bennett Adelson Creating 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("type", "home"); phone1.InnerText = "206-555-0144"; XmlElement postal = doc.CreateElement("postal"); postal.InnerText = "68042"; XmlElement address = doc.CreateElement("address"); address.AppendChild(postal); XmlElement contact = doc.CreateElement("contact"); contact.AppendChild(name); contact.AppendChild(phone1); contact.AppendChild(address); XmlElement contacts = doc.CreateElement("contacts"); contacts.AppendChild(contact); doc.AppendChild(contacts); Bennett Adelson Creating 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) Bennett Adelson Traditional 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(@"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"); } } Bennett Adelson LINQ 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); Bennett Adelson Casting and Filtering on an Attribute string xml = "<order >" + "<item price='150'>Motor</item>" + "<item price='50'>Cable</item>" + "<item price='50'>Modem</item>" + "<item price='250'>Monitor</item>" + "<item price='10'>Mouse</item>" + "</order>"; XElement order = XElement.Parse(xml); var query = from i in order.Elements("item") where (int)i.Attribute("price") > 100 select i; foreach(var result in query) Console.WriteLine("Expensive Item {0} costs {1}", (string)result, (string)result.Attribute("price")); Bennett Adelson Transforms 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”) > 500,000 select new XElement("tr", new XElement("td", (string)customer.Attribute("CustomerID")), new XElement("td", (string)customer.Element("Contact"))); XElement html = new XElement("html", new XElement("table", header, rows)); Console.Write(html); Bennett Adelson XLINQ 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")))) Bennett Adelson Creating an XElement from an XML Literal • Wouldn’t you rather do this? Dim contacts As XElement = _ <contacts> <contact> <name>Fred Blogs</name> <phone type="home">206-555-0144</phone> <phone type="work">425-555-0145</phone> <address> <street1>123 Main St</street1> <city>Mercer Island</city> <state>WA</state> <postal>98040</postal> </address> </contact> </contacts> • • Compiler converts this to same code as previous slide No need for line continuation characters within the XML Bennett Adelson VB XML Literals Can Contain Expressions Evaluated at Runtim • Element Value from Variable Dim name As XElement = <name><%=someVariable%></name> • Element Value from Function Call Dim name As XElement = <name><%=SomeFunction()%></name> • Attribute Value from Variable Dim phone as XElement = <phone type=(someVariable)>234-5678</phone> • Element Name from Variable Dim contact as XElement = <contact> <(someVariable)>Foo</> </contact> Bennett Adelson Embedding XLINQ Query Inside XML Literal Dim contacts as XElement = _ <contacts> <%= _Select _ <contact> <name><%=CStr(c.name(0))%></name> <%=c.phone %> <address><%=c.address%></address> <contact/> From c In contacts %> </contacts> Bennett Adelson XLINQ 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: “@” • 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 Bennett Adelson Late Bound XML Example For Each Dim phone In contact.phone Console.WriteLine(CStr(phone.@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))) Bennett Adelson Schema-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 Bennett Adelson The Adventure Continues! Bennett Adelson LINQ Resources on the Web • LINQ Official Site – http://msdn.microsoft.com/netframework/f uture/linq • Barry Gervin’s LINQ Resources – http://objectsharp.com/blogs/barry/archive /2005/09/13/3395.aspx Bennett Adelson Q&A Bennett Adelson