• Tidak ada hasil yang ditemukan

Pro LINQ free ebook download ee ee

N/A
N/A
Protected

Academic year: 2019

Membagikan "Pro LINQ free ebook download ee ee"

Copied!
746
0
0

Teks penuh

(1)

Pro

LINQ

Language Integrated Query in VB 2008

Joseph C. Rattz, Jr.

and

Dennis Hayes

Learn to use the power of Microsoft’s

ground-breaking new technology.

(2)
(3)

Pro LINQ

Language Integrated Query

in VB 2008

(4)

All rights reserved. No part of this work may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording, or by any information storage or retrieval system, without the prior written permission of the copyright owner and the publisher.

ISBN-13 (pbk): 978-1-4302-1644-5

ISBN-13 (electronic): 978-1-4302-1645-2

Printed and bound in the United States of America 9 8 7 6 5 4 3 2 1

Trademarked names may appear in this book. Rather than use a trademark symbol with every occurrence of a trademarked name, we use the names only in an editorial fashion and to the benefit of the trademark owner, with no intention of infringement of the trademark.

Lead Editor: Ewan Buckingham Technical Editor: Joseph C. Rattz, Jr.

Technical Reviewers: Joseph C. Rattz, Jr., Fabio Ferracchiati

Editorial Board: Clay Andres, Steve Anglin, Mark Beckner, Ewan Buckingham, Tony Campbell, Gary Cornell, Jonathan Gennick, Michelle Lowman, Matthew Moodie, Jeffrey Pepper, Frank Pohlmann, Ben Renow-Clarke, Dominic Shakeshaft, Matt Wade, Tom Welsh Project Manager: Richard Dal Porto

Copy Editor: Heather Lang

Associate Production Director: Kari Brooks-Copony Production Editor: Kelly Winquist

Compositors: Dina Quan, Patrick Cunningham Proofreader: April Eddy

Indexer: Carol Burbo Artist: April Milne

Cover Designer: Kurt Krames

Manufacturing Director: Tom Debolski

Distributed to the book trade worldwide by Springer-Verlag New York, Inc., 233 Spring Street, 6th Floor, New York, NY 10013. Phone 1-800-SPRINGER, fax 201-348-4505, e-mail kn`ano)ju<olnejcan)o^i*_ki, or visitdppl6++sss*olnejcankjheja*_ki.

For information on translations, please contact Apress directly at 2855 Telegraph Avenue, Suite 600, Berkeley, CA 94705. Phone 510-549-5930, fax 510-549-5939, e-mail ejbk<]lnaoo*_ki, or visit dppl6++sss* ]lnaoo*_ki.

Apress and friends of ED books may be purchased in bulk for academic, corporate, or promotional use. eBook versions and licenses are also available for most titles. For more information, reference our Special Bulk Sales–eBook Licensing web page at dppl6++sss*]lnaoo*_ki+ejbk+^qhgo]hao.

The information in this book is distributed on an “as is” basis, without warranty. Although every precau-tion has been taken in the preparaprecau-tion of this work, neither the author(s) nor Apress shall have any liability to any person or entity with respect to any loss or damage caused or alleged to be caused directly or indi-rectly by the information contained in this work.

(5)

in C# 2008. Unfortunately, Art’s health began to fail toward the end of that book, and for a while, it seemed doubtful he would live to see it completed. Not one to give up, Art

over-came numerous hospitalizations and did indeed receive his personally signed copy. Sadly, Art will never see this book because he passed away on February 25, 2009, at the

(6)

iv

Contents at a Glance

About the Author

. . . xxiii

About the Technical Reviewer

. . . xxv

Acknowledgments

. . . .xxvii

PART 1

฀ ฀

Pro LINQ: Language Integrated Query

in VB.NET 2008

CHAPTER 1

Hello LINQ

. . . 3

CHAPTER 2

VB.NET 2008 Language Enhancements for LINQ

. . . 21

PART 2

฀ ฀

LINQ to Objects

CHAPTER 3

LINQ to Objects Introduction

. . . 81

CHAPTER 4

Deferred Operators

. . . 93

CHAPTER 5

Nondeferred Operators

. . . 177

PART 3

฀ ฀

LINQ to XML

CHAPTER 6

LINQ to XML Introduction

. . . 241

CHAPTER 7

The LINQ to XML API

. . . 247

CHAPTER 8

LINQ to XML Operators

. . . 337

(7)

v

CHAPTER 10

LINQ to DataSet Operators

. . . 413

CHAPTER 11

Additional DataSet Capabilities

. . . 453

Part 5

฀ ฀

LINQ to SQL

CHAPTER 12

LINQ to SQL Introduction

. . . 463

CHAPTER 13

LINQ to SQL Tips and Tools

. . . 477

CHAPTER 14

LINQ to SQL Database Operations

. . . 505

CHAPTER 15

LINQ to SQL Entity Classes

. . . 553

CHAPTER 16

The DataContext

. . . 599

CHAPTER 17

Concurrency Conflicts

. . . 663

CHAPTER 18

Additional SQL Capabilities

. . . 681

(8)
(9)

vii

Contents

About the Author

. . . xxiii

About the Technical Reviewer

. . . xxv

Acknowledgments

. . . .xxvii

PART 1

฀ ฀

Pro LINQ: Language Integrated

Query in VB.NET 2008

CHAPTER 1

Hello LINQ

. . . 3

A Paradigm Shift

. . . 4

Query XML

. . . 4

Query a SQL Server Database

. . . 6

Introduction to LINQ

. . . 7

LINQ Is About Data Queries

. . . 8

Components

. . . 8

LINQ to Objects

. . . 8

LINQ to XML

. . . 9

LINQ to DataSet

. . . 9

LINQ to SQL

. . . 9

LINQ to Entities

. . . 9

How to Obtain LINQ

. . . 9

LINQ Is Not Just for Queries

. . . 10

Tips to Get You Started

. . . 13

Use Dim Without Specifying the Type When Confused

. . . 13

Use the Cast or OfType Operators for Legacy Collections

. . . 15

Prefer the OfType Operator to the Cast Operator

. . . 16

Don’t Assume a Query Is Bug Free

. . . 16

Take Advantage of Deferred Queries

. . . 17

Use the DataContext Log

. . . 18

Use the LINQ Forum

. . . 19

(10)

CHAPTER 2

VB.NET 2008 Language Enhancements for LINQ

. . . 21

New VB.NET 2008 Language Additions

. . . 21

New (and Not So New) Options

. . . 22

Option Explicit

. . . 22

Option Compare

. . . 23

Option Strict

. . . 23

Option Infer

. . . 24

Lambda Expressions

. . . 24

Using Named Methods

. . . 25

Using Lambda Expressions

. . . 26

Expression Trees

. . . 29

Keyword Dim, Object Initialization, and Anonymous Types

. . . 30

The Implicitly Typed Local Variable Keyword Dim

(with Option Infer On/Option Strict On)

. . . 31

Object Initialization Expressions

. . . 33

Anonymous Types

. . . 34

Extension Methods

. . . 38

Instance (Object) vs. Shared (Class) Methods Recap

. . . 38

The Problem Solved by Extension Methods

. . . 40

The Solution

. . . 41

Extension Method Declarations and Invocations

. . . 42

Extension Method Precedence

. . . 43

Partial Methods

. . . 43

A Partial Method Example

. . . 44

What Is the Point of Partial Methods?

. . . 46

The Rules

. . . 47

Query Expressions

. . . 47

Query Expression Grammar

. . . 49

Query Expression Translation

. . . 51

Nullable Value Types

. . . 60

XML Enhancements

. . . 61

XML Literals

. . . 61

XML Embedded Expressions

. . . 64

XML Axis Properties

. . . 67

XML Namespace Imports

. . . 74

(11)

PART 2

฀ ฀

LINQ to Objects

CHAPTER 3

LINQ to Objects Introduction

. . . 81

LINQ to Objects Overview

. . . 81

IEnumerable(Of T), Sequences, and the Standard Query Operators

. . . 82

Returning IEnumerable(Of T) and Deferred Queries

. . . 83

Func Delegates

. . . 87

The Standard Query Operators Alphabetical Cross-Reference

. . . 88

A Tale of Two Syntaxes

. . . 90

Summary

. . . 90

CHAPTER 4

Deferred Operators

. . . 93

Referenced Namespaces

. . . 93

Referenced Assemblies

. . . 93

Query Expression Syntax vs. Standard Dot Notation Syntax

. . . 94

Common Classes

. . . 94

The Deferred Operators by Purpose

. . . 96

Restriction

. . . 96

Where

. . . 96

Projection

. . . 99

Select

. . . 99

SelectMany

. . . 105

Partitioning

. . . 110

Take

. . . 110

TakeWhile

. . . 113

Skip

. . . 115

SkipWhile

. . . 116

Concatenation

. . . 119

Concat

. . . 119

Ordering

. . . 122

OrderBy

. . . 123

OrderByDescending

. . . 129

ThenBy

. . . 132

ThenByDescending

. . . 137

(12)

Join

. . . 142

Join

. . . 142

GroupJoin

. . . 144

Grouping

. . . 146

GroupBy

. . . 146

Set

. . . 152

Distinct

. . . 153

Union

. . . 154

Intersect

. . . 156

Except

. . . 157

Conversion

. . . 159

Cast

. . . 159

OfType

. . . 161

AsEnumerable

. . . 164

Element

. . . 167

DefaultIfEmpty

. . . 167

Generation

. . . 172

Range

. . . 172

Repeat

. . . 173

Empty

. . . 174

Summary

. . . 175

CHAPTER 5

Nondeferred Operators

. . . 177

Referenced Namespaces

. . . 177

Common Classes

. . . 177

The Nondeferred Operators by Purpose

. . . 180

Conversion

. . . 181

ToArray

. . . 181

ToList

. . . 183

ToDictionary

. . . 185

ToLookup

. . . 190

Equality

. . . 195

SequenceEqual

. . . 195

Element

. . . 199

First

. . . 199

FirstOrDefault

. . . 201

Last

. . . 203

LastOrDefault

. . . 205

(13)

SingleOrDefault

. . . 209

ElementAt

. . . 211

ElementAtOrDefault

. . . 212

Quantifiers

. . . 213

Any

. . . 214

All

. . . 216

Contains

. . . 217

Aggregate

. . . 220

Count

. . . 220

LongCount

. . . 222

Sum

. . . 224

Min

. . . 226

Max

. . . 229

Average

. . . 232

Aggregate

. . . 234

Summary

. . . 238

PART 3

฀ ฀

LINQ to XML

CHAPTER 6

LINQ to XML Introduction

. . . 241

Additional Advantages of LINQ to XML

. . . 244

Cheating the W3C DOM XML API

. . . 244

Summary

. . . 246

CHAPTER 7

The LINQ to XML API

. . . 247

Referenced Namespaces

. . . 247

Significant API Design Enhancements

. . . 248

XML Tree Construction Simplified with

Functional Construction

. . . 248

Document Centricity Eliminated in Favor of

Element Centricity

. . . 251

Names, Namespaces, and Prefixes

. . . 253

Node Value Extraction

. . . 255

The LINQ to XML Object Model

. . . 258

(14)

XML Creation

. . . 262

Creating XML with XML Literals

. . . 263

Creating Elements with XElement

. . . 263

Creating Attributes with XAttribute

. . . 266

Creating Comments with XComment

. . . 267

Creating Containers with XContainer

. . . 268

Creating Declarations with XDeclaration

. . . 268

Creating Document Types with XDocumentType

. . . 269

Creating Documents with XDocument

. . . 270

Creating Names with XName

. . . 271

Creating Namespaces with XNamespace

. . . 272

Creating Nodes with XNode

. . . 272

Creating Processing Instructions with XProcessingInstruction

. . . 273

Creating Streaming Elements with XStreamingElement

. . . 275

Creating Text with XText

. . . 276

Creating CData with XCData

. . . 277

XML Output

. . . 277

Saving with XDocument.Save()

. . . 277

Saving with XElement.Save()

. . . 279

XML Input

. . . 280

Loading with XDocument.Load()

. . . 280

Loading with XElement.Load()

. . . 282

Parsing with XDocument.Parse() or XElement.Parse()

. . . 282

XML Traversal

. . . 283

Traversal Properties

. . . 284

Forward with XNode.NextNode

. . . 284

Backward with XNode.PreviousNode

. . . 285

Up to Document with XObject.Document

. . . 286

Up with XObject.Parent

. . . 287

Traversal Methods

. . . 288

Down with XContainer.Nodes()

. . . 288

Down with XContainer.Elements()

. . . 292

Down with XContainer.Element()

. . . 294

Up Recursively with XNode.Ancestors()

. . . 295

Up Recursively with XElement.AncestorsAndSelf()

. . . 296

Down Recursively with XContainer.Descendants()

. . . 297

Down Recursively with XElement.DescendantsAndSelf()

. . . 298

Forward with XNode.NodesAfterSelf()

. . . 298

Forward with XNode.ElementsAfterSelf()

. . . 300

Backward with XNode.NodesBeforeSelf()

. . . 300

(15)

XML Modification

. . . 302

Adding Nodes

. . . 303

XContainer.Add() (AddLast)

. . . 303

XContainer.AddFirst()

. . . 304

XNode.AddBeforeSelf()

. . . 305

XNode.AddAfterSelf()

. . . 307

Deleting Nodes

. . . 308

XNode.Remove()

. . . 308

IEnumerable(Of T).Remove()

. . . 309

XElement.RemoveAll()

. . . 310

Updating Nodes

. . . 311

XElement.Value on XElement Objects, XText.Value

on XText Objects, and XComment.Value on

XComment Objects

. . . 311

XDocumentType.Name, XDocumentType.PublicId,

XDocumentType.SystemId, and XDocumentType.

InternalSubset on XDocumentType Objects

. . . 313

XProcessingInstruction.Target on XProcessingInstruction

Objects and XProcessingInstruction.Data on

XProcessingInstruction Objects

. . . 313

XElement.ReplaceAll()

. . . 314

XElement.SetElementValue() on Child XElement Objects

. . . 315

XML Attributes

. . . 317

Attribute Creation

. . . 317

Attribute Traversal

. . . 317

Forward with XElement.FirstAttribute

. . . 317

Forward with XAttribute.NextAttribute

. . . 318

Backward with XAttribute.PreviousAttribute

. . . 318

Backward with XElement.LastAttribute

. . . 319

XElement.Attribute()

. . . 319

XElement.Attributes()

. . . 320

Attribute Modification

. . . 321

Adding Attributes

. . . 321

Deleting Attributes

. . . 321

Updating Attributes

. . . 324

XElement.SetAttributeValue()

. . . 325

XML Annotations

. . . 327

Adding Annotations with XObject.AddAnnotation()

. . . 327

(16)

Removing Annotations with XObject.RemoveAnnotations()

. . . 327

Annotations Example

. . . 328

XML Events

. . . 331

XObject.Changing

. . . 331

XObject.Changed

. . . 332

An Event Example

. . . 332

Trick or Treat, or Undefined?

. . . 335

Summary

. . . 335

CHAPTER 8

LINQ to XML Operators

. . . 337

Introduction to LINQ to XML Operators

. . . 337

Ancestors

. . . 338

Declarations

. . . 338

Examples

. . . 339

AncestorsAndSelf

. . . 343

Declarations

. . . 343

Examples

. . . 344

Attributes

. . . 346

Declarations

. . . 346

Examples

. . . 347

DescendantNodes

. . . 348

Declarations

. . . 349

Examples

. . . 349

DescendantNodesAndSelf

. . . 350

Declarations

. . . 350

Examples

. . . 351

Descendants

. . . 352

Declarations

. . . 352

Examples

. . . 352

DescendantsAndSelf

. . . 354

Declarations

. . . 355

Examples

. . . 355

Elements

. . . 357

Declarations

. . . 358

Examples

. . . 358

InDocumentOrder

. . . 360

Declarations

. . . 360

(17)

Nodes

. . . 362

Declarations

. . . 362

Examples

. . . 362

Remove

. . . 363

Declarations

. . . 363

Examples

. . . 364

Summary

. . . 366

CHAPTER 9

Additional XML Capabilities

. . . 369

Referenced Namespaces

. . . 369

Queries

. . . 370

No Reaching

. . . 370

A Complex Query

. . . 373

Transformations

. . . 379

Transformations Using XSLT

. . . 379

Transformations Using Functional Construction

. . . 381

Tips On XML Transformations Using LINQ

. . . 384

Simplify Complex Tasks with Helper Methods

. . . 384

Suppressing Node Construction with Nothing

. . . 385

Handling Multiple Peer Nodes While Remaining Flat

. . . 388

Validation

. . . 391

The Extension Methods

. . . 391

Declarations

. . . 391

Obtaining an XML Schema

. . . 393

Examples

. . . 395

XPath

. . . 406

Declarations

. . . 406

Examples

. . . 408

Summary

. . . 409

PART 4

฀ ฀

LINQ to DataSet

CHAPTER 10

LINQ to DataSet Operators

. . . 413

Assembly References

. . . 414

Referenced Namespaces

. . . 414

(18)

DataRow Set Operators

. . . 416

Distinct

. . . 416

Declarations

. . . 416

Examples

. . . 417

Except

. . . 420

Declarations

. . . 421

Examples

. . . 421

Intersect

. . . 423

Declarations

. . . 423

Examples

. . . 423

Union

. . . 425

Declarations

. . . 425

Examples

. . . 426

SequenceEqual

. . . 427

Declarations

. . . 428

Examples

. . . 428

DataRow Field Operators

. . . 429

Field(Of T)

. . . 435

Declarations

. . . 435

Examples

. . . 436

SetField(Of T)

. . . 440

Declarations

. . . 440

Examples

. . . 441

DataTable Operators

. . . 444

AsEnumerable

. . . 444

Declarations

. . . 444

Examples

. . . 444

CopyToDataTable(Of DataRow)

. . . 445

Declarations

. . . 445

Examples

. . . 446

Summary

. . . 451

CHAPTER 11

Additional DataSet Capabilities

. . . 453

Required Namespaces

. . . 453

Typed DataSets

. . . 453

Putting It All Together

. . . 455

(19)

PART 5

฀ ฀

LINQ to SQL

CHAPTER 12

LINQ to SQL Introduction

. . . 463

Introducing LINQ to SQL

. . . 464

The DataContext

. . . 466

Entity Classes

. . . 466

Associations

. . . 467

Concurrency Conflict Detection

. . . 468

Concurrency Conflict Resolution

. . . 468

Prerequisites for Running the Examples

. . . 469

Obtaining the Appropriate Version of the Northwind Database

. . . 469

Generating the Northwind Entity Classes

. . . 469

Generating the Northwind XML Mapping File

. . . 471

Importing the Generated Code

. . . 471

Using the LINQ to SQL API

. . . 472

IQueryable(Of T)

. . . 472

Some Common Methods

. . . 473

GetStringFromDb()

. . . 473

ExecuteStatementInDb()

. . . 474

Summary

. . . 474

CHAPTER 13

LINQ to SQL Tips and Tools

. . . 477

Introduction to LINQ to SQL Tips and Tools

. . . 477

Tips

. . . 478

Use the DataContext.Log Property

. . . 478

Use the GetChangeSet() Method

. . . 479

Consider Using Partial Classes or Mapping Files

. . . 479

Consider Using Partial Methods

. . . 480

Tools

. . . 480

SqlMetal

. . . 480

XML Mapping File vs. DBML Intermediate File

. . . 485

Working with DBML Intermediate Files

. . . 486

The Object Relational Designer

. . . 487

Creating Your LINQ to SQL Classes File

. . . 487

Connecting the DataContext to the Database

. . . 489

Adding an Entity Class

. . . 490

(20)

Adding Objects to the Entity Class Model

. . . 494

Overriding the Insert, Update, and Delete Methods

. . . 495

Use SqlMetal and the O/R Designer Together

. . . 502

Summary

. . . 503

CHAPTER 14

LINQ to SQL Database Operations

. . . 505

Prerequisites for Running the Examples

. . . 505

Some Common Methods

. . . 505

Using the LINQ to SQL API

. . . 506

Standard Database Operations

. . . 506

Inserts

. . . 506

Inserting Attached Entity Objects

. . . 509

Queries

. . . 511

Exceptions to the Norm

. . . 512

Associations

. . . 514

Joins

. . . 527

Deferred Query Execution

. . . 532

The SQL IN Statement with the Contains Operator

. . . 536

Updates

. . . 537

Updating Associated Classes

. . . 537

Deletes

. . . 541

Deleting Attached Entity Objects

. . . 543

Deleting Relationships

. . . 543

Overriding Database Modification Statements

. . . 544

Overriding the Insert Method

. . . 545

Overriding the Update Method

. . . 545

Overriding the Delete Method

. . . 545

Example

. . . 545

Overriding in the Object Relational Designer

. . . 548

Considerations

. . . 548

SQL Translation

. . . 549

Summary

. . . 551

CHAPTER 15

LINQ to SQL Entity Classes

. . . 553

Prerequisites for Running the Examples

. . . 553

Entity Classes

. . . 553

Creating Entity Classes

. . . 553

Generating Entity Classes

. . . 554

Writing Entity Classes By Hand

. . . 554

(21)

XML External Mapping File Schema

. . . 583

Projecting into Entity Classes vs. Nonentity Classes

. . . 583

Prefer Object Initialization to Parameterized

Construction When Projecting

. . . 586

Extending Entity Classes with Partial Methods

. . . 589

Important System.Data.Linq API Classes

. . . 591

EntitySet(Of T)

. . . 591

EntityRef(Of T)

. . . 592

Entity

. . . 592

HasLoadedOrAssignedValue

. . . 593

Table(Of T)

. . . 594

IExecuteResult

. . . 594

ReturnValue

. . . 595

GetParameterValue

. . . 595

ISingleResult(Of T)

. . . 595

ReturnValue

. . . 596

IMultipleResults

. . . 596

ReturnValue

. . . 597

GetResult(Of T)

. . . 597

Summary

. . . 598

CHAPTER 16

The DataContext

. . . 599

Prerequisites for Running the Examples

. . . 599

Some Common Methods

. . . 599

Using the LINQ to SQL API

. . . 599

[Your]DataContext Class

. . . 599

The DataContext Class

. . . 600

The DataContext Class Implements IDisposable

. . . 603

Primary Purposes

. . . 603

Identity Tracking

. . . 603

Change Tracking

. . . 609

Change Processing

. . . 610

The DataContext Lifetime

. . . 610

DataContext() and [Your]DataContext()

. . . 611

Declarations

. . . 611

Examples

. . . 612

Creating Mapping Sources

. . . 624

SubmitChanges()

. . . 624

Declarations

. . . 624

(22)

DatabaseExists()

. . . 631

Declarations

. . . 632

Examples

. . . 632

CreateDatabase()

. . . 632

Declarations

. . . 633

Examples

. . . 633

DeleteDatabase()

. . . 634

Declarations

. . . 634

Examples

. . . 634

CreateMethodCallQuery()

. . . 635

Declarations

. . . 635

Examples

. . . 635

ExecuteQuery()

. . . 637

Declarations

. . . 637

Examples

. . . 637

Translate()

. . . 639

Declarations

. . . 639

Examples

. . . 640

ExecuteCommand()

. . . 641

Declarations

. . . 641

Examples

. . . 641

ExecuteMethodCall()

. . . 642

Declarations

. . . 642

Examples

. . . 643

GetCommand()

. . . 650

Declarations

. . . 650

Examples

. . . 651

GetChangeSet()

. . . 652

Declarations

. . . 652

Examples

. . . 652

GetTable()

. . . 654

Declarations

. . . 654

Examples

. . . 654

Refresh()

. . . 655

Declarations

. . . 655

Examples

. . . 656

(23)

CHAPTER 17

Concurrency Conflicts

. . . 663

Prerequisites for Running the Examples

. . . 663

Some Common Methods

. . . 663

Using the LINQ to SQL API

. . . 663

Concurrency Conflicts

. . . 663

Optimistic Concurrency

. . . 664

Conflict Detection

. . . 664

Conflict Resolution

. . . 668

Pessimistic Concurrency

. . . 675

An Alternative Approach for N-Tier Architectures

. . . 678

Summary

. . . 680

CHAPTER 18

Additional SQL Capabilities

. . . 681

Prerequisites for Running the Examples

. . . 681

Using the LINQ to SQL API

. . . 681

Using the LINQ to XML API

. . . 681

Database Views

. . . 681

Entity Class Inheritance

. . . 683

Transactions

. . . 689

Summary

. . . 691

(24)
(25)

xxiii

About the Author

JOSEPH C. RATTZ, JR. unknowingly began his career in software development in 1990 when a friend asked him for assistance writing an ANSI text editor named ANSI Master for the Com-modore Amiga. A hangman game (The Gallows) soon followed. From these compiled Basic programs, he moved on to programming in C for more speed and power. Joe then developed applications that were sold to JumpDisk, an Amiga disk magazine, as well as Amiga World

magazine. Due to developing in a small town on a fairly isolated platform, Joe learned all the wrong ways to write code. It was while trying to upgrade his poorly written applications that he gained respect for the importance of easily maintainable code. It was love at first sight when Joe spotted a source-level debugger in use for the first time.

Two years later, Joe obtained his first software development opportunity at Policy Management Systems Corporation as an entry-level programmer developing a client/server insurance application for OS/2 and Presentation Manager. Through the years, he added C++, Unix, Java, ASP, ASP.NET, C#, HTML, DHTML, and XML to his skill set while develop-ing applications for SCT, DocuCorp, IBM and the Atlanta Committee for the Olympic Games, CheckFree, NCR, EDS, Delta Technology, Radiant Systems, and the Genuine Parts Company. Joe enjoys the creative aspects of user interface design, and he appreciates the discipline nec-essary for server-side development. But, given his druthers, his favorite development pastime is debugging code.

Joe can be found working for the Genuine Parts Company—the parent company of NAPA—in the Automotive Parts Group Information Systems department, where he works on his baby, the Storefront web site. This site for NAPA stores provides a view into their accounts and data on a network of AS/400s.

Joe’s first book, Pro LINQ: Language Integrated Query in C# 2008, was published on November 19, 2007, which is the exact same date that Visual Studio 2008 was released to man-ufacturing. One final LINQ coincidence is that Visual Studio 2008 was officially launched on February 27, 2008, which just happens to be Joe’s birthday.

(26)
(27)

xxv

About the Technical Reviewer

(28)
(29)

xxvii

Acknowledgments

W

ell, it appears that it is time to write the acknowledgments for another book. Readers of

Pro LINQ: Language Integrated Query in C# 2008 may recall the endless delays in publishing that book. A project that initially started as a 9-month project grew into a 17-month project. This book turned out to be no less challenging in terms of scheduling and delays. If you were one of those who patiently waited for this book to be published, I want to thank you for your patience. I hope you find it worth the wait.

When I wrote the acknowledgments for my C# LINQ book, I expected that to be my single opportunity to show my appreciation to all those people who made the book possible. I did not imagine that I would have another opportunity to write acknowledgments, so I spilled my guts on the first one. Obviously, most of the people who made the C# book possible also made this one possible. The beauty of writing this book’s acknowledgments is that I have the luxury of getting to correct any errors of omission that occurred in the first book’s Acknowledgments. The first person that I want to thank is my wife, Vickey. I mentioned in the first book that she had to do many of my chores during the 17 months I worked on it. Then, a mere 7 months after it was published, I was engaged in yet another book—for a year. She has waited more than long enough for us to resume a normal life. I have promised her that I will straighten the basement before I begin any more books. So this may be my last.

I would like to thank Apress for another opportunity to write a book. Specifically, I want to thank Ewan Buckingham. I can’t help but think I have taken years off his life. Richard Dal Porto performed project management duties for this book and with chapters flying about, it is amazing that he could keep it all straight. Heather Lang handled the role of copy editor. She also took over the reins as copy editor on my C# LINQ book, so I have been twice privileged to have her make my writing look coherent, well-formed, and written in a language consist-ing of characters other than commas. Sadly, I still haven’t learned when to use commas. Kelly Winquist was the production editor for this book, and I certainly appreciate her and her team’s effort, which is apparent when you get to see the finished product. I turn in Microsoft Word documents, and a book comes out on the other side. It is a fabulous machine! Thank you April Eddy for proofreading the book once I was finished with it. I know there are unnamed others who worked on this book, and while you don’t get to see your name here, you get the more valuable benefit of probably never having had an interaction with me. Kudos to you too!

Next, I must extend my appreciation to Fabio Ferracchiati. Not only did he perform the technical reviewer duties, he filled in as stunt author. This book still might not be finished were it not for his assistance.

(30)

I want to thank the Microsoft VB language team for wonderful LINQ support being added to the language. Your VB.NET XML enhancements are enough to make this C# programmer envious. I hope the C# design team was paying attention.

Again, I must thank my parents: my dad for giving me the confidence to think I could actually write a book, and my mom for her constant input of ideas.

Last, I want to thank all the readers of the C# LINQ book who sent in comments, sug-gestions, and corrections. Specifically, I want to thank Jon Skeet and Judson White for their much-appreciated effort. Both of these fine developers took the time to send me detailed notes. This book is better because of their efforts.

(31)
(32)
(33)

3

Hello LINQ

Listing 1-1. Hello LINQ

KlpekjAtlhe_epKj KlpekjEjbanKj KlpekjOpne_pKj

EilknpoOuopai EilknpoOuopai*Hejm

Ik`qhaIk`qha-Oq^I]ej$%

@eicnaapejco$%=oOpnejc9wdahhksknh`(dahhkHEJM(dahhk=lnaooy

@eiepaio9[

BnkioEjcnaapejco[ Sdanao*Aj`oSepd$HEJM%[ Oaha_po

BknA]_depaiEjepaio ?kjokha*SnepaHeja$epai% Jatpepai

Aj`Oq^ Aj`Ik`qha

Note

The code in Listing 1-1 is a complete console program created in Visual Studio 2008. In most places, I will leave out the Ik`qha,Oq^I]ej, and common Eilknpo statements, but I will include any unusualEilknpo that an example requires.

(34)

dahhkHEJM

Note

Also note that, in most cases, you do not need to have the common Eilknpo statements in your code, because VB.NET adds them behind the scenes at compile time. You can see (and modify) the list of namespaces added by looking in the project’s Properties, on the Reference tab, in the “Imported namespaces” table.

A Paradigm Shift

Did you just feel your world shift? As a .NET developer, you should have. With the trivial pro-gramming example in Listing 1-1, you just ran what somewhat appears to be a Structured Query Language (SQL) query on an array of strings.1 Check out that sdana clause. Did you

notice that I used the Aj`oSepd method of a Opnejc object? You may be wondering why, with

KlpekjOpne_pKj, an error was not generated when I declared epaio without a type or when I used epai as a variable in the BknA]_d loop without giving it a type. To those used to pro-gramming in VB6 or VB.NET with KlpekjAtlhe_ep and KlpekjOpne_p set toKbb, declaring a variable without giving it a type may not seem like a big deal. But with KlpekjOpne_pKj, it is. Explaining why we do not get a compilation error from this would be a distraction right now, but I will pick up this idea again at the start of Chapter 2. So, what features of VB.NET are allowing all of this? The answer is Microsoft’s Language Integrated Query, otherwise known as LINQ.

Query XML

While the example in Listing 1-1 is trivial, the example in Listing 1-2 may begin to indicate the potential power that LINQ puts into the hands of the .NET developer. It displays the ease with which one can interact with and query Extensible Markup Language (XML) data utilizing the LINQ to XML API. You should pay particular attention to how I construct the XML data into an object named ^kkgo that I can programmatically interact with.

Listing 1-2. A Simple XML Query Using LINQ to XML

EilknpoOuopai EilknpoOuopai*Hejm EilknpoOuopai*Tih*Hejm

@ei^kkgo=oTAhaiajp9[ 8^kkgo:

(35)

8^kkg:

8pepha:LnkHEJM6H]jcq]caEjpacn]pa`MqanuejR>*JAP.,,48+pepha: 8]qpdkn:@ajjeoD]uao8+]qpdkn:

8+^kkg: 8^kkg:

8pepha:LnkSB6Sej`ksoSkngbhksej*JAP/*18+pepha: 8]qpdkn:>nq_a>qgkre_o8+]qpdkn:

8+^kkg: 8^kkg:

8pepha:Lnk?.,,4]j`pda*JAP/*1Lh]pbkni(BkqnpdA`epekj8+pepha: 8]qpdkn:=j`nasPnkahoaj8+]qpdkn:

8+^kkg: 8+^kkgo:

#?Opn_]opjkpjaa`a`ebKlpekjOpne_peokbb @eipephao9[

Bnki^kkgEj^kkgo*Ahaiajpo$^kkg%[

Sdana?Opn$^kkg*Ahaiajp$]qpdkn%%9@ajjeoD]uao[ Oaha_p^kkg*Ahaiajp$pepha%

BknA]_dpephaEjpephao

?kjokha*SnepaHeja$pepha*R]hqa% Jatppepha

Note

The code in Listing 1-2 requires adding the Ouopai*Tih*Hejm*`hh assembly to the project refer-ences if it is not already added. Also notice that I added an Eilknpo statement for the Ouopai*Tih*Hejm

namespace.

Running the previous code by pressing Ctrl+F5 outputs the following data to the console window:

LnkHEJM6H]jcq]caEjpacn]pa`MqanuejR>*JAP.,,4

Did you notice how I simply loaded the XML data into an object of type TAhaiajp? Among the new features in VB.NET 2008 are XML literals, where a block of XML can be assigned to an XML element. I will cover this in more detail in Chapter 2. Also, LINQ to XML expands the XML API with its richer API. While the W3C Document Object Model (DOM) XML API requires

Tih@k_qiajp-centric development, LINQ to XML allows the developer to interact at the ele-ment level using the TAhaiajp class. The LINQ to XML API will be covered in Chapter 7.

(36)

Again notice that I utilized the same SQL-like syntax to query the XML data, as though it were a database.

Query a SQL Server Database

My next example shows how to use LINQ to SQL to query database2 tables. In Listing 1-3, I

query the standard Microsoft Northwind sample database.

Listing 1-3. A Simple Database Query Using LINQ to SQL

EilknpoOuopai EilknpoOuopai*Hejm EilknpoOuopai*@]p]*Hejm

Eilknpo?d]lpan-*jsej`

@ei`^=oJasJknpdsej`$[

@]p]Okqn_a9*XOMHATLNAOO7Ejepe]h?]p]hkc9Jknpdsej`7Ejpacn]pa`Oa_qnepu9OOLE7%

@ei_qopo9[

Bnki_Ej`^*?qopkiano[

Sdana_*?epu9Nek`aF]jaenk[ Oaha_p_

BknA]_d_qopEj_qopo

?kjokha*SnepaHeja$w,y(_qop*?kil]juJ]ia% Jatp_qop

Note

The code in Listing 1-3 requires adding the Ouopai*@]p]*Hejm*`hh assembly to the project refer-ences if it is not already added. Also notice that I added an Eilknpo statement for the Ouopai*@]p]*Hejm

namespace.

When working with the files generated by SqlMetal, you need to use namespaces and Eilknpo state-ments that are appropriate for the way to set up your project. Depending on how you set up your project, you may need to include the project’s default namespace, such as Eilknpo?d]lpan-*jsej`, just the gener-ated namespace, Eilknpojsej`, or you may not need any Eilknpo statement at all. I cover this in more detail in Chapter 2.

You can see that I added an Eilknpo statement for the ?d]lpan-*jsej` namespace. For this example to work, you must use the SqlMetal command-line utility, or the Object Relational Designer, to generate entity classes for the targeted database, which in this example is the Microsoft Northwind sample database. See Chapter 12 to read how this is done with SqlMetal.

(37)

The generated entity classes are created in the jsej` namespace, which I specify when gen-erating them. I then add the SqlMetal generated source module to my project and add the

Eilknpo statement for the jsej` namespace.

Note

You may need to change the connection string that is passed to the Jknpdsej` constructor in Listing 1-3 for the connection to be properly made. Read the section on @]p]?kjpatp$% and

WUkqnY@]p]?kjpatp$% in Chapter 16 to see different ways to connect to the database.

Running the previous code by pressing Ctrl+F5 outputs the following data to the console window:

D]j]ne?]njao Mqa@ahŽ_e] Ne_]n`k=`k_e_]`ko

This simple example demonstrates querying the Customers table of the Northwind data-base for customers in Rio de Janeiro. While it may appear that there is nothing new or special going on here that I wouldn’t already have with existing means, there are some significant differences. Most noticeably, this query is integrated into the language, and this means I get language-level support, which includes syntax checking and IntelliSense. Gone will be the days of writing a SQL query into a string and not detecting a syntax error until runtime. Want to make your sdana clause dependent on a field in the Customers table but you cannot remember the name of the field? IntelliSense will show the table’s fields to you. Once you type

c.in the previous example, IntelliSense will display all the fields of the Customers table to you. All of the previous queries use the query expression syntax. You will learn in Chapter 2 that there are two syntaxes available for LINQ queries, of which the query expression syntax is one. Of course, you may always use the standard dot notation syntax that you are accustomed to seeing in .NET instead. This syntax is the normal k^fa_p*iapdk`$% invocation pattern you have always been using.

Introduction to LINQ

As the Microsoft .NET platform, and its supporting languages C# and VB.NET, have matured, it has become apparent that one of the more troublesome areas still remaining for developers is that of accessing data from different data sources. In particular, database access and XML manipulation are often cumbersome at best, and problematic in the worst cases.

(38)

unanticipated error behavior. Having database code that is not validated at compile time can certainly lead to this problem.

A second problem is the nuisance caused by the differing data types utilized by a par-ticular data domain, such as database or XML data types vs. the native language in which the program is written. In particular, dates and times can be quite a hassle.

XML parsing, iterating, and manipulation can be quite tedious. Often an XML fragment is all that is desired, but due to the W3C DOM XML API, an Tih@k_qiajp must be created just to perform various operations on the XML fragment.

Rather than just add more classes and methods to address these deficiencies in a piece-meal fashion, the development team at Microsoft decided to go one step further by abstracting the fundamentals of data query from these particular data domains. The result was LINQ. LINQ is Microsoft’s technology to provide a language-level support mechanism for querying data of all types. These types include in-memory arrays and collections, databases, XML docu-ments, and more.

LINQ Is About Data Queries

For the most part, LINQ is all about queries, whether they are queries returning a set of matching objects, a single object, or a subset of fields from an object or set of objects. In LINQ, this returned set of objects is called a sequence. Most LINQ sequences are of type

EAjqian]^ha$KbP%, where P is the data type of the objects stored in the sequence. For example, if you have a sequence of integers, they would be stored in a variable of type EAjqian]^ha$Kb Ejpacan%. You will see that EAjqian]^ha$KbP% runs rampant in LINQ. Many of the LINQ meth-ods return an EAjqian]^ha$KbP%.

In the previous examples, all of the queries actually return an EAjqian]^ha$KbP% or a type that inherits from EAjqian]^ha$KbP%. However, I declare the variables without types for the sake of simplicity at this point. This is unrelated to the old VB6 R]ne]jp or to how VB.NET has handled untyped variables prior to VB.NET 2008, because these variables are given a specific type by VB.NET. I will cover this in detail in Chapter 2, where you will see examples that begin demonstrating that sequences are truly stored in variables implementing the EAjqian]^ha$Kb P% interface.

Components

Because LINQ is so powerful, you should expect to see a lot of systems and products become LINQ compatible. Virtually any data store would make a good candidate for supporting LINQ queries. This includes databases, Microsoft’s Active Directory, the registry, the file system, an Excel file, and so on.

Microsoft has already identified the components in this section as necessary for LINQ. There is no doubt that there will be more to come.

LINQ to Objects

(39)

LINQ to XML

LINQ to XML is the name given to the LINQ API dedicated to working with XML. This interface was known as XLinq in older prereleases of LINQ. Not only has Microsoft added the neces-sary XML libraries to work with LINQ, it has addressed other deficiencies in the standard XML DOM, thereby making it easier than ever to work with XML. Gone are the days of having to cre-ate an Tih@k_qiajp just to work with a small piece of XML. To take advantage of LINQ to XML, you must have a reference to the Ouopai*Tih*Hejm*`hh assembly in your project and have an

Eilknpo statement such as the following:

EilknpoOuopai*Tih*Hejm

LINQ to DataSet

LINQ to DataSet is the name given to the LINQ API for DataSets. Many developers have a lot of existing code relying on DataSets. Those who do will not be left behind, nor will they need to rewrite their code to take advantage of the power of LINQ.

LINQ to SQL

LINQ to SQL is the name given to the EMqanu]^ha$KbP% API that allows LINQ queries to work with Microsoft’s SQL Server database. This interface was known as DLinq in older prereleases of LINQ. To take advantage of LINQ to SQL, you must have a reference to the Ouopai*@]p]* Hejm*`hh assembly in your project and have anEilknpo statement such as the following:

EilknpoOuopai*@]p]*Hejm

LINQ to Entities

LINQ to Entities is an alternative LINQ API that is used to interface with a database using the ADO.NET Entity Framework. It decouples the entity object model from the physical database by injecting a logical mapping between the two. With this decoupling comes increased power and flexibility, as well as complexity. Because LINQ to Entities appears to be outside the core LINQ framework, it is not covered in this book. However, if you find that you need more flexi-bility than LINQ to SQL permits, it would be worth considering as an alternative. Specifically, if you need looser coupling between your entity object model and database, entity objects com-posed of data coming from multiple tables, or more flexibility in modeling your entity objects, LINQ to Entities may be your answer.

How to Obtain LINQ

(40)

LINQ Is Not Just for Queries

Maybe by definition you could say LINQ is just for queries because it stands for Language Inte-grated Query. But please don’t think of it only in that context. Its power transcends mere data queries. I prefer to think of LINQ as a data iteration engine, but perhaps Microsoft didn’t want a technology named DIE.

Have you ever called a method and it returned data back in some data structure that you then needed to convert to yet another data structure before you could pass it to another method? Let’s say for example you call method A, and method A returns an array of type

Opnejc that contains numeric values stored as strings. You then need to call method B, but method B requires an array of integers. You normally end up writing a loop to iterate through the array of strings and populate a newly constructed array of integers. What a nuisance. Allow me to point out the power of Microsoft’s LINQ.

Let’s pretend I have an array of strings that I received from some method A, as shown in Listing 1-4.

Listing 1-4. Converting an Array of Strings to Integers

@eijqi^ano$%=oOpnejc9w,,0.(,-,(5(.3y

For this example, I’ll just statically declare an array of strings. Now before I call method B, I need to convert the array of strings to an array of integers:

@eijqio$%=oEjpacan9jqi^ano*Oaha_p$Bqj_pekj$o%Ejp/.*L]noa$o%%*Pk=nn]u$%

That’s it. How much easier could it get? Even just saying “abracadabra” only saves you 65 characters. Here is some code to display the resulting array of integers:

BknA]_djqi=oEjpacanEjjqio ?kjokha*SnepaHeja$jqi% Jatpjqi

Here is the output showing the integers:

0. -, 5 .3

I know what you are thinking: maybe I just trimmed off the leading zeros. If I sort it, will you then be convinced? If they were still strings, 9 would be at the end, and 10 would be first. Listing 1-5 contains some code to do the conversion and sort the output.

Listing 1-5. Converting an Array of Strings to Integers and Sorting It

@eijqi^ano$%=oOpnejc9w,,0.(,-,(5(.3y

@eijqio$%=oEjpacan9[

(41)

BknA]_djqi=oEjpacanEjjqio ?kjokha*SnepaHeja$jqi% Jatpjqi

Here are the results:

5 -, .3 0.

How slick is that? “OK,” you say, “that is nice, but it sure is a simple example.” Now, I’ll give you a more complex example.

Let’s say you have some common code that contains an Ailhkuaa class. In that Ailhkuaa

class is a method to return all the employees. Also assume you have another code base of com-mon code that contains a ?kjp]_p class, and in that class is a method to publish contacts. Let’s assume you have the assignment to publish all employees as contacts.

The task seems simple enough, but there is a catch. The common Ailhkuaa method that retrieves the employees returns the employees in an =nn]uHeop of Ailhkuaa objects, and the

?kjp]_p method that publishes contacts requires an array of type ?kjp]_p. Here is that com-mon code:

J]iaol]_aHEJM@ar*DN Lq^he_?h]ooAilhkuaa Lq^he_e`=oEjpacan Lq^he_benopJ]ia=oOpnejc Lq^he_h]opJ]ia=oOpnejc

Lq^he_Od]na`Bqj_pekjCapAilhkuaao$%=o=nn]uHeop

#Kb_kqnoapdana]h_k`askqh`lnk^]^hu^ai]gejc]`]p]^]oamqanu #necdp]^kqpdana*

@ei]h=oJas=nn]uHeop$%

#I]j(`kpdajasR>*JAPk^fa_pejepe]hev]pekjba]pqnaoi]gapdeo #]oj]l*

]h*=``$JasAilhkuaaSepdw[

*e`9-(*benopJ]ia9@ajjeo(*h]opJ]ia9D]uaoy% ]h*=``$JasAilhkuaaSepdw[

*e`9.(*benopJ]ia9Sehhe]i(*h]opJ]ia9C]paoy% ]h*=``$JasAilhkuaaSepdw[

*e`9/(*benopJ]ia9=j`ano(*h]opJ]ia9Dafho^ancy%

(42)

J]iaol]_aHEJM@ar*?kiikj Lq^he_?h]oo?kjp]_p Lq^he_E`=oEjpacan Lq^he_J]ia=oOpnejc

Lq^he_Od]na`Oq^Lq^heod?kjp]_po$>uR]h_kjp]_po$%=o?kjp]_p% #Pdeolq^heodiapdk`fqopsnepaopdaipkpda_kjokhasej`ks* BknA]_d_=o?kjp]_pEj_kjp]_po

?kjokha*SnepaHeja$?kjp]_pE`6w,y?kjp]_p6w-y(_*E`(_*J]ia% Jatp_

Aj`Oq^ Aj`?h]oo Aj`J]iaol]_a

As you can see, the Ailhkuaa class and CapAilhkuaao method are in one namespace,

HEJM@ar*DN, and the CapAilhkuaao method returns an =nn]uHeop. The Lq^heod?kjp]_po method is in another namespace, HEJM@ar*?kiikj, and requires an array of ?kjp]_p objects to be passed.

Previously, this always meant iterating through the =nn]uHeop returned by the

CapAilhkuaao method and creating a new array of type ?kjp]_p to be passed to the

Lq^heod?kjp]_po method. LINQ makes it easy, as shown in Listing 1-6.

Listing 1-6. Calling the Common Code

@ei]hAilhkuaao=o=nn]uHeop9HEJM@ar*DN*Ailhkuaa*CapAilhkuaao$%

@ei_kjp]_po$%=oHEJM@ar*?kiikj*?kjp]_p9[ ]hAilhkuaao[

*?]op$KbHEJM@ar*DN*Ailhkuaa%$%[

*Oaha_p$Bqj_pekj$a%JasHEJM@ar*?kiikj*?kjp]_p[ Sepdw[

*E`9a*e`([

*J]ia9Opnejc*Bkni]p$w,yw-y(a*benopJ]ia(a*h]opJ]ia%[y%[ *Pk=nn]u$%

HEJM@ar*?kiikj*?kjp]_p*Lq^heod?kjp]_po$_kjp]_po%

To convert the =nn]uHeop of Ailhkuaa objects to an array of ?kjp]_p objects, I first cast the

=nn]uHeop of Ailhkuaa objects to an EAjqian]^ha$KbAilhkuaa% sequence using the ?]op Stan-dard Query Operator. This is necessary because the legacy =nn]uHeop collection class was used. Syntactically speaking, objects of the Ouopai*K^fa_p class type are stored in an =nn]uHeop, not objects of the Ailhkuaa class type. So I must cast them to Ailhkuaa objects. Had the

CapAilhkuaao method returned a generic Heop collection, this would not have been necessary. However, that collection type was not available when this legacy code was written.

Next, I call the Oaha_p operator on the returned sequence of Ailhkuaa objects and in the

(43)

A lambda expression is a new VB.NET 2008 feature that allows new shorthand for specifying anonymous methods that I will explain in Chapter 2. Last, I convert the sequence of newly constructed?kjp]_p objects to an array of ?kjp]_p objects using the Pk=nn]u operator because that is what the Lq^heod?kjp]_po method requires. Isn’t that slick? Here are the results:

?kjp]_pE`6-?kjp]_p6@ajjeoD]uao ?kjp]_pE`6.?kjp]_p6Sehhe]iC]pao ?kjp]_pE`6/?kjp]_p6=j`anoDafho^anc

As you can see, LINQ can do a lot besides just querying data. As you read through the chapters of this book, try to think of additional uses for the features LINQ provides.

Tips to Get You Started

While working with LINQ to write this book, I often found myself confused, befuddled, and stuck. While there are many very useful resources available to the developer wanting to learn to use LINQ to its fullest potential, I want to offer a few tips to get you started. In some ways, these tips feel like they should come at the end of the book. After all, I haven’t even explained what some of these concepts are at this point. But it would seem a bit sadistic to make you read the full text of the book first, only to offer the tips at the end. So with that said, this section contains some tips I think you might find useful, even if you do not fully understand them or the context.

Use Dim Without Specifying the Type When Confused

While it is necessary to use the @ei keyword without specifying a type when capturing a sequence of anonymous classes to a variable, sometimes it is a convenient way to get code to compile if you are confused. While I am very much in favor of developers knowing exactly what type of data is contained in a sequence—meaning that for EAjqian]^ha$KbP% you should know what data type P is—sometimes, especially when just starting with LINQ, it can get con-fusing. If you find yourself stuck, where code will not compile because of some sort of data type mismatch, consider removing the data type from the @ei statement.

For example, let’s say you have the following code:

#Pdeo_k`asehhjkp_kileha*

@ei`^=oJasJknpdsej`$@]p]Okqn_a9*XOMHATLNAOO7Ejepe]h?]p]hkc9Jknpdsej`%

@eikn`ano=oEAjqian]^ha$;%9`^*?qopkiano[

*Sdana$Bqj_pekj$_%_*?kqjpnu9QO==j`=hok_*NacekjEoS=%[ *Oaha_pI]ju$Bqj_pekj$_%_*Kn`ano%

(44)

Listing 1-7. Code Sample Using the Dim Keyword Without Specifing the Type

@ei`^=oJasJknpdsej`$@]p]Okqn_a9*XOMHATLNAOO7Ejepe]h?]p]hkc9Jknpdsej`%

@eikn`ano9`^*?qopkiano[

*Sdana$Bqj_pekj$_%_*?kqjpnu9QO==j`=hok_*NacekjEoS=%[ *Oaha_pI]ju$Bqj_pekj$_%_*Kn`ano%

?kjokha*SnepaHeja$kn`ano*CapPula$%%

In this example, please notice that the kn`ano variable type is now not specified. Running this code produces the following:

Ouopai*@]p]*Hejm*@]p]Mqanu\-W?d]lpan-*jsej`*Kn`anY

There is a lot of compiler gobbledygook there, but the important part is the jsej`*Kn`an

portion. You now know that the data type you are getting a sequence of is jsej`*Kn`an. So you could rewrite the previous code, plus enumerate through the results, as shown in Listing 1-8.

Listing 1-8. Sample Code from Listing 1-7 Except with Explicit Types

@ei`^=oJasJknpdsej`$[

@]p]Okqn_a9*XOMHATLNAOO7Ejepe]h?]p]hkc9Jknpdsej`7Ejpacn]pa`Oa_qnepu9OOLE7%

@eikn`ano=oEAjqian]^ha$KbKn`an%9`^*?qopkiano[

*Sdana$Bqj_pekj$_%_*?kqjpnu9QO==j`=hok_*NacekjEoS=%[ *Oaha_pI]ju$Bqj_pekj$_%_*Kn`ano%

BknA]_depai=oKn`anEjkn`ano ?kjokha*SnepaHeja$[

w,y)w-y)w.y([ epai*Kn`an@]pa([ epai*Kn`anE@([ epai*OdelJ]ia% Jatpepai

Note

For the previous code to work, you will need to have an Eilknpo statement for the Ouopai* ?khha_pekjo*Cajane_ namespace, in addition to the Ouopai*Hejm namespace you should always expect to have when LINQ code is present.

This code would produce the following abbreviated results:

(45)

Å

0+-3+-554-.6,,6,,=I)--,/.)Sdepa?hkranI]ngapo 1+-+-554-.6,,6,,=I)--,22)Sdepa?hkranI]ngapo

Use the Cast or OfType Operators for Legacy Collections

You will find that the majority of LINQ’s Standard Query Operators can only be called on collections implementing the EAjqian]^ha$KbP% interface. None of the legacy .NET collec-tions—those in the Ouopai*?khha_pekj namespace—implement EAjqian]^ha$KbP%. So the question becomes, how do you use LINQ with legacy collections in your existing code base?

There are two Standard Query Operators specifically for this purpose, ?]op and KbPula. Both of these operators can be used to convert legacy collections to EAjqian]^ha$KbP%

sequences. Listing 1-9 shows an example.

Listing 1-9. Converting a Legacy Collection to an IEnumerable(Of T) Using the Cast Operator

#E#hh_na]pa]hac]_u_khha_pekj* @ei]nn]uHeop=o=nn]uHeop9[

Jas=nn]uHeop$JasK^fa_p$%w=`]io(=npdqn(>q_d]j]jy%

@eij]iao=oEAjqian]^ha$KbOpnejc%9[

]nn]uHeop*?]op$KbOpnejc%$%*Sdana$Bqj_pekj$j%j*Hajcpd83%

BknA]_dj]ia=oOpnejcEjj]iao ?kjokha*SnepaHeja$j]ia% Jatpj]ia

Listing 1-10 shows the same example using the KbPula operator.

Listing 1-10. Using the OfType Operator

#E#hh_na]pa]hac]_u_khha_pekj* @ei]nn]uHeop=o=nn]uHeop9[

Jas=nn]uHeop$JasK^fa_p$%w=`]io(=npdqn(>q_d]j]jy%

@eij]iao=oEAjqian]^ha$KbOpnejc%9[

]nn]uHeop*KbPula$KbOpnejc%$%*Sdana$Bqj_pekj$j%j*Hajcpd83%

BknA]_dj]ia=oOpnejcEjj]iao ?kjokha*SnepaHeja$j]ia% Jatpj]ia

Both examples provide the exact same results. Here they are:

(46)

The difference between the two operators is that the ?]op operator will attempt to cast every element in the collection to the specified type to be put into the output sequence. If there is a type in the collection that cannot be cast to the specified type, an exception will be thrown. This makes the ?]op operator excellent for enforcing the data type of objects in a col-lection. The KbPula operator will only attempt to put those elements that can be cast to the type specified into the output sequence. This makes the KbPula operator excellent for filtering a collection by data type.

Prefer the OfType Operator to the Cast Operator

One of the most important reasons why generics were added to .NET was to give the lan-guage the ability to have data collections with static type checking. Prior to generics—barring creating your own specific collection type for every type of data for which you wanted a collection—there was no way to ensure that every element in a legacy collection, such as an

=nn]uHeop, a D]odp]^ha, and so on, was of the same and correct type. Nothing in the language prevented code from adding a Patp^kt object to an =nn]uHeop meant to contain only H]^ah

objects.

With the introduction of generics in .NET 2.0, .NET developers now have a way to explic-itly state that a collection can only contain elements of a specified type. While either the

KbPula or ?]op operator may work for a legacy collection, ?]op requires that every object in the collection be of the correct type. When using the ?]op operator, if any object is unable to be cast to the specified data type, an exception is thrown. If there is any legitimate possibility that objects of differing types exist in the collection, use the KbPula operator. With it, only objects of the specified type will be stored in the output EAjqian]^ha$KbP% sequence, and no exception will be thrown. The best-case scenario is that every object will be of the specified type and be in the output sequence. The worst case is that some elements will get skipped, but they would have thrown an exception had the ?]op operator been used instead.

Don’t Assume a Query Is Bug Free

In Chapter 3, I discuss that LINQ queries are often deferred and not actually executed when it appears you are calling them. For example, consider this code fragment from Listing 1-1:

@eiepaio9[

BnkioEjcnaapejco[ Sdanao*Aj`oSepd$HEJM%[ Oaha_po

BknA]_depaiEjepaio ?kjokha*SnepaHeja$epai% Jatpepai

(47)

It is often easy to forget that many of the query operators are deferred and will not execute until a sequence is enumerated. This means you could have an improperly written query that will throw an exception when the resulting sequence is eventually enumerated. That enumera-tion could take place far enough downstream that it is easily forgotten that a query may be the culprit.

Let’s examine the code in Listing 1-11.

Listing 1-11. Query with Intentional Exception Deferred Until Enumeration

@eiopnejco$%=oOpnejc9wkja(psk(Jkpdejc(pdnaay

?kjokha*SnepaHeja$>abknaSdana$%eo_]hha`*%

@eieaOpnejco=oEAjqian]^ha$KbOpnejc%9opnejco*Sdana$Bqj_pekj$o%o*Hajcpd9/% ?kjokha*SnepaHeja$=bpanSdana$%eo_]hha`*%

BknA]_do=oOpnejcEjeaOpnejco ?kjokha*SnepaHeja$Lnk_aooejc"o% Jatpo

I know that the third element in the array of strings is Jkpdejc, and I cannot call Jkpdejc* Hajcpd without throwing an exception. The execution steps over the line of code calling the query just fine. It is not until I enumerate the sequence eaOpnejco, and specifically the third element, that the exception occurs. Here are the results of this code:

>abknaSdana$%eo_]hha`* =bpanSdana$%eo_]hha`* Lnk_aooejckja

Lnk_aooejcpsk

Qjd]j`ha`At_alpekj6Ouopai*JqhhNabanaj_aAt_alpekj6K^fa_pnabanaj_ajkpoappk]j ejop]j_akb]jk^fa_p*

Å

As you can see, I called the Sdana operator without exception. It’s not until I try to enu-merate the third element of the sequence that an exception is thrown. Now imagine if that sequence,eaOpnejco, is passed to a function that downstream enumerates the sequence, perhaps to populate a drop-down list or some other control. It would be easy to think the exception is caused by a fault in that function, not the LINQ query itself.

Take Advantage of Deferred Queries

In Chapter 3, I go into deferred queries in more depth. However, I want to point out that if a query is a deferred query that ultimately returns an EAjqian]^ha$KbP%, that EAjqian]^ha$KbP%

object can be enumerated over, time and time again, obtaining the latest data from the data source. You don’t need to actually call or, as I earlier pointed out, declare the query again.

In most of the code samples in this book, you will see a query called and an

(48)

code is executed multiple times, calling the actual query each time is needless work. It might make more sense to have a query initialization method that gets called once for the lifetime of the scope and to construct all the queries there. Then, you could enumerate over a particular sequence to get the latest version of the query results at will.

Use the DataContext Log

When working with LINQ to SQL, don’t forget that the database class that is generated by SqlMetal inherits from Ouopai*@]p]*Hejm*@]p]?kjpatp. This means that your generated

@]p]?kjpatp class has some useful built-in functionality, such as a PatpSnepan property namedHkc.

One of the niceties of the Hkc object is that it will output the equivalent SQL statement of anEMqanu]^ha$KbP% query prior to the parameter substitution. Have you ever had code break in production that you think might be data related? Wouldn’t it be nice if there was a way to get the query executed against the database, so that you could enter it in SQL Server Enterprise Manager or Query Analyzer and see the exact data coming back? The @]p]?kjpatp’sHkc object will output the SQL query for you. An example is shown in Listing 1-12.

Listing 1-12. An Example Using the DataContext.Log Object

@ei`^=oJasJknpdsej`$[

@]p]Okqn_a9*XOMHATLNAOO7Ejepe]h?]p]hkc9Jknpdsej`7Ejpacn]pa`Oa_qnepu9OOLE7%

`^*Hkc9?kjokha*Kqp

@eikn`ano=oEMqanu]^ha$KbKn`an%9[ Bnki_Ej`^*?qopkiano[

BnkikEj_*Kn`ano[

Sdana_*?kqjpnu9QO==j`=hok_*NacekjEoS=[ Oaha_pk

BknA]_depai=oKn`anEjkn`ano

?kjokha*SnepaHeja$w,y)w-y)w.y(epai*Kn`an@]pa(epai*Kn`anE@(epai*OdelJ]ia% Jatpepai

This code produces the following output:

OAHA?PWp-Y*WKn`anE@Y(Wp-Y*W?qopkianE@Y(Wp-Y*WAilhkuaaE@Y(Wp-Y*WKn`an@]paY( Wp-Y*WNamqena`@]paY(Wp-Y*WOdella`@]paY(

Wp-Y*WOdelRe]Y(Wp-Y*WBnaecdpY(Wp-Y*WOdelJ]iaY(Wp-Y*WOdel=``naooY( Wp-Y*WOdel?epuY(Wp-Y*WOdelNacekjY(Wp-Y*WOdelLkop]

h?k`aY(Wp-Y*WOdel?kqjpnuY

BNKIW`^kY*W?qopkianoY=OWp,Y(W`^kY*WKn`anoY=OWp-Y

SDANA$Wp,Y*W?kqjpnuY9<l,%=J@$Wp,Y*WNacekjY9<l-%=J@$Wp-Y*W?qopkianE@Y9 Wp,Y*W?qopkianE@Y%

))<l,6EjlqpJR]n?d]n$Oeva9/7Lna_9,7O_]ha9,%WQO=Y ))<l-6EjlqpJR]n?d]n$Oeva9.7Lna_9,7O_]ha9,%WS=Y

(49)

))?kjpatp6OmhLnkre`an$Omh.,,4%Ik`ah6=ppne^qpa`Iap]Ik`ah>qeh`6/*1*/,3.5*-/+.-+-553-.6,,6,,=I)-,04.)H]vuGGkqjpnuOpkna 1+..+-553-.6,,6,,=I)-,101)H]vuGGkqjpnuOpkna

2+-5+-553-.6,,6,,=I)-,130)Pn]eh#oDa]`CkqniapLnkreoekjano 2+./+-553-.6,,6,,=I)-,133)Pn]eh#oDa]`CkqniapLnkreoekjano -+4+-554-.6,,6,,=I)-,4..)Pn]eh#oDa]`CkqniapLnkreoekjano 3+/-+-552-.6,,6,,=I)-,.25)Sdepa?hkranI]ngapo

--+-+-552-.6,,6,,=I)-,/00)Sdepa?hkranI]ngapo /+-,+-553-.6,,6,,=I)-,025)Sdepa?hkranI]ngapo /+.0+-553-.6,,6,,=I)-,04/)Sdepa?hkranI]ngapo 0+--+-553-.6,,6,,=I)-,1,0)Sdepa?hkranI]ngapo 3+--+-553-.6,,6,,=I)-,152)Sdepa?hkranI]ngapo -,+2+-553-.6,,6,,=I)-,25/)Sdepa?hkranI]ngapo -,+4+-553-.6,,6,,=I)-,252)Sdepa?hkranI]ngapo -,+/,+-553-.6,,6,,=I)-,3./)Sdepa?hkranI]ngapo --+-/+-553-.6,,6,,=I)-,30,)Sdepa?hkranI]ngapo -+/,+-554-.6,,6,,=I)-,42-)Sdepa?hkranI]ngapo .+.0+-554-.6,,6,,=I)-,5,0)Sdepa?hkranI]ngapo 0+-3+-554-.6,,6,,=I)--,/.)Sdepa?hkranI]ngapo 1+-+-554-.6,,6,,=I)--,22)Sdepa?hkranI]ngapo

Use the LINQ Forum

Despite providing the best tips I can think of, there will more than likely be times when you get stuck. Don’t forget that there is a forum dedicated to LINQ at MSDN.com. You can find a link to it here: dppl6++sss*hejm`ar*_ki. This forum is monitored by Microsoft developers, and you will find a wealth of knowledgeable resources there.

Summary

I sense that by now you are chomping at the bit to move on to the next chapter, but before you do, I want to remind you of a few things.

First, LINQ is going to change the way .NET developers query data. Vendors will more than likely be lining up to add a “LINQ Compatible” sticker to their products, just like they cur-rently do with XML.

Bear in mind that LINQ is not just a new library to be added to your project. It is a total approach to querying data that comprises several components depending on the data store being queried. At the present time, you can use LINQ to query the following data sources: in-memory data collections using LINQ to Objects, XML using LINQ to XML, DataSets using LINQ to DataSet, and SQL Server databases using LINQ to SQL.

Also, please remember what I said about LINQ being for more than just queries. In a sample project I have been working on using LINQ, I have found LINQ very useful not only for querying data but for getting data into the necessary format for presentation in a WinForm control.

(50)
(51)

VB.NET 2008 Language

Enhancements for LINQ

I

n the previous chapter, I introduced you to LINQ. I provided some examples to whet your appetite and shared some premature tips. You may be perplexed though by some of the syntax. If so, it is probably because the VB.NET you witnessed in that chapter is new and improved. The reason for the VB.NET language upgrade is that VB.NET 2005 just didn’t have the muscle to pull off LINQ. In this chapter, I introduce you to the more powerful VB.NET 2008.

Please be aware that in this book, when I use the term VB.NET 2008, I am referring to VB.NET 9.0, which is shipped with Visual Studio 2008. So technically, the features I am cover-ing in this chapter are in the VB.NET 9.0 language specification.

New VB.NET 2008 Language Additions

To make LINQ seamlessly integrate with VB.NET, significant enhancements were needed for the VB.NET language. Virtually every significant enhancement to the VB.NET language made in version 2008 was made specifically to support LINQ. While all of these features have merit on their own, it is really the sum of the parts contributing to LINQ that makes VB.NET 2008 so noteworthy.

To truly understand much of the syntax of LINQ, it is necessary for me to cover some of the new VB.NET 2008 language features before proceeding with the workings of the compo-nents of LINQ. This chapter will cover the following language additions:

Ê UÊ iÜʜ«Ìˆœ˜Ã Ê UÊ >“L`>ÊiÝ«ÀiÃȜ˜Ã Ê UÊ Ý«ÀiÃȜ˜ÊÌÀiiÃ

Ê UÊ /…iʘiÜÊÕÃ>}iʜvÊ̅iÊ@ei keyword

Ê UÊ "LiVÌʈ˜ˆÌˆ>ˆâ>̈œ˜Ê>˜`Ê>˜œ˜Þ“œÕÃÊÌÞ«iÃ Ê UÊ ÝÌi˜Ãˆœ˜Ê“i̅œ`Ã

Gambar

Table 2-1. Translation Step Variables
Table 2-2. XML Axis Properties
Table 3-1. Standard Query Operators Alphabetical Cross-Reference
Table 3-1. Continued
+7

Referensi

Dokumen terkait

[r]

Carefully, thoughtfully, and sympathetically. These words sum up the best approach to reading poetry. The economy and compression of poetry mean that every part of the poem must

Guru untuk anak dan remaja dengan kelainan penglihatan dapat memilih kemampuan yang otonom comparatif, sebagai guru dalam intenerant program atau layanan pengetahuan

Akhmad Faisal Hidayat, Hubungan Regulasi Diri dengan Prestasi Belajar Kalkulus II Ditinjau dari Aspek Metakognisi, Motivasi dan Perilaku, (Jurnal Elektronik

Kesimpulan : berdasarkan hasil wawancara dapat sisimpulkan bahwa siswa kelas V SD 2 Honggosoco terindikasi mengalami kesulitan belajar pada mata pelajaran matematika terutama

Selaku Dekan Fakultas Teknologi Industri Universitas Katolik Soegijapranata yang telah memberikan saran serta masukan dalam pelaksanaan Tugas Akhir ini.. Bapak Yulianto

Dengan demikian dapat disimpulkan bahwa model pembelajaran Cooperative tipe Group Investigation dapat meningkatkan rasa ingin tahu dan keterampilan menulis pengumuman

Untuk memperoleh data motivasi belajar siswa yaitu dengan menggunakan angket motivasi belajar, sedangkan untuk memperoleh data prestasi belajar dalam penelitian ini menggunakan