Download the full version of the ebook now at ebookultra.com
Programming Entity Framework DbContext 1st
Edition Julia Lerman
https://ebookultra.com/download/programming-
entity-framework-dbcontext-1st-edition-julia-
lerman/
Explore and download more ebook at https://ebookultra.com
Recommended digital products (PDF, EPUB, MOBI) that
you can download immediately if you are interested.
Professional ADO NET 3 5 with LINQ and the Entity
Framework 1st Edition Roger Jennings
https://ebookultra.com/download/professional-ado-net-3-5-with-linq-
and-the-entity-framework-1st-edition-roger-jennings/
ebookultra.com
Julia High Performance Programming Learning Path 1st
Edition Ivo Balbaert
https://ebookultra.com/download/julia-high-performance-programming-
learning-path-1st-edition-ivo-balbaert/
ebookultra.com
Database Design Using Entity Relationship Diagrams 1st
Edition Sikha Bagui
https://ebookultra.com/download/database-design-using-entity-
relationship-diagrams-1st-edition-sikha-bagui/
ebookultra.com
Kierkegaard 1st Edition Julia Watkin
https://ebookultra.com/download/kierkegaard-1st-edition-julia-watkin/
ebookultra.com
Needlework 1st Edition Julia Watts
https://ebookultra.com/download/needlework-1st-edition-julia-watts/
ebookultra.com
Gene Cloning 1st Edition Julia Lodge
https://ebookultra.com/download/gene-cloning-1st-edition-julia-lodge/
ebookultra.com
Julia High performance 1st Edition Avik Sengupta
https://ebookultra.com/download/julia-high-performance-1st-edition-
avik-sengupta/
ebookultra.com
Powers A History 1st Edition Julia Jorati
https://ebookultra.com/download/powers-a-history-1st-edition-julia-
jorati/
ebookultra.com
Learning to Think Strategically 1st Edition Julia Sloan
https://ebookultra.com/download/learning-to-think-strategically-1st-
edition-julia-sloan/
ebookultra.com
Programming Entity Framework DbContext 1st Edition
Julia Lerman Digital Instant Download
Author(s): Julia Lerman, Rowan Miller
ISBN(s): 9781449312961, 1449312969
Edition: 1
File Details: PDF, 7.20 MB
Year: 2012
Language: english
Programming Entity Framework:
DbContext
Julia Lerman and Rowan Miller
Beijing • Cambridge • Farnham • Köln • Sebastopol • Tokyo
Programming Entity Framework: DbContext
by Julia Lerman and Rowan Miller
Copyright © 2012 Julia Lerman and Rowan Miller. All rights reserved.
Printed in the United States of America.
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions
are also available for most titles (http://my.safaribooksonline.com). For more information, contact our
corporate/institutional sales department: (800) 998-9938 or corporate@oreilly.com.
Editors: Meghan Blanchette and
Rachel Roumeliotis
Production Editor: Teresa Elsey
Cover Designer: Karen Montgomery
Interior Designer: David Futato
Illustrators: Robert Romano and Rebecca Demarest
Revision History for the First Edition:
2012-02-23 First release
See http://oreilly.com/catalog/errata.csp?isbn=9781449312961 for release details.
Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of
O’Reilly Media, Inc. Programming Entity Framework: DbContext, the image of a great African heron,
and related trade dress are trademarks of O’Reilly Media, Inc.
Many of the designations used by manufacturers and sellers to distinguish their products are claimed as
trademarks. Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a
trademark claim, the designations have been printed in caps or initial caps.
While every precaution has been taken in the preparation of this book, the publisher and authors assume
no responsibility for errors or omissions, or for damages resulting from the use of the information con-
tained herein.
ISBN: 978-1-449-31296-1
[LSI]
1330008698
Table of Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix
1. Introducing the DbContext API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Getting the DbContext API into Your Project 2
Looking at Some Highlights of the DbContext API 3
Reducing and Simplifying Ways to Work with a Set 5
Retrieving an Entity Using ID with DbSet.Find 5
Avoiding Trolling Around the Guts of Entity Framework 6
Working with the BreakAway Model 6
Getting the Sample Solution 6
Getting DbContext from an EDMX Model 8
Ensuring DbContext Instances Get Disposed 11
2. Querying with DbContext . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Writing Queries with LINQ to Entities 13
Querying All the Data from a Set 16
Using LINQ for Sorting, Filtering, and More 18
Finding a Single Object 21
Querying Local Data 24
Using the Load Method to Bring Data into Memory 26
Running LINQ Queries Against Local 27
Working with the ObservableCollection Returned by Local 29
Loading Related Data 30
Lazy Loading 31
Eager Loading 33
Explicit Loading 36
Checking If a Navigation Property Has Been Loaded 38
Querying Contents of a Collection Navigation Property 39
Explicit Loading a Subset of the Contents of a Navigation Property 41
iii
3. Adding, Changing, and Deleting Entities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Working with Single Entities 44
Adding New Entities 44
Changing Existing Entities 45
Deleting Existing Entities 46
Multiple Changes at Once 51
The “Find or Add” Pattern 52
Working with Relationships 53
Adding a Relationship Between Objects 54
Changing a Relationship Between Objects 56
Removing a Relationship Between Objects 57
Working with Change Tracking 59
Using Snapshot Change Tracking 60
Understanding When Automatic Change Detection Occurs 60
Controlling When DetectChanges Is Called 60
Using DetectChanges to Trigger Relationship Fix-up 63
Enabling and Working with Change Tracking Proxies 64
Ensuring the New Instances Get Proxies 67
Creating Proxy Instances for Derived Types 68
Fetching Entities Without Change Tracking 69
4. Working with Disconnected Entities Including N-Tier Applications . . . . . . . . . . . . . 71
A Simple Operation on a Disconnected Graph 72
Exploring the Challenges of N-Tier 74
Using Existing N-Tier Frameworks That Support Graph Modification 76
Using Explicit Operations on the Server Side 77
Replaying Changes on the Server 77
Understanding How DbContext Responds to Setting the State of a Single
Entity 78
Marking a New Entity as Added 79
Marking an Existing Entity as Unchanged 80
Marking an Existing Entity as Modified 81
Registering an Existing Entity for Deletion 83
Working with Relationships with and Without Foreign Keys 85
Setting the State for Multiple Entities in an Entity Graph 88
Getting the Graph into the Context 88
Setting the State of Entities in a Graph 90
Building a Generic Approach to Track State Locally 92
Creating a Generic Method That Can Apply State Through Any Graph 96
Concurrency Implications 98
Tracking Individually Modified Properties 99
Recording Modified Property Names 99
Recording Original Values 102
iv | Table of Contents
Querying and Applying Changes 106
5. Change Tracker API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
Change Tracking Information and Operations for a Single Entity 111
Working with the State Property 112
Working with Current, Original, and Database Values 113
Working with DbPropertyValues for Complex Types 119
Copying the Values from DbPropertyValues into an Entity 122
Changing Values in a DbPropertyValues 123
Working with Individual Properties 128
Working with Scalar Properties 128
Working with Complex Properties 131
Working with Navigation Properties 133
Refreshing an Entity from the Database 137
Change Tracking Information and Operations for Multiple Entities 139
Using the Change Tracker API in Application Scenarios 141
Resolving Concurrency Conflicts 141
Logging During Save Changes 147
6. Validating with the Validation API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
Defining and Triggering Validation: An Overview 154
Validating a Single Object on Demand with GetValidationResult 155
Specifying Property Rules with ValidationAttribute Data Annotations 157
Validating Facets Configured with the Fluent API 158
Validating Unmapped or “Transient” Properties 158
Validating Complex Types 159
Using Data Annotations with an EDMX Model 159
Inspecting Validation Result Details 160
Inspecting Individual Validation Errors 161
Exploring More ValidationAttributes 163
Using CustomValidationAttributes 164
Validating Individual Properties on Demand 166
Specifying Type-Level Validation Rules 166
Using IValidatableObject for Type Validation 167
Validating Multiple Rules in IValidatableObject 169
Using CustomValidationAttributes for Type Validation 171
Understanding How EF Combines Validations 173
Validating Multiple Objects 175
Validating When Saving Changes 178
Reviewing ObjectContext. SaveChanges Workflow 179
Understanding DbContext.SaveChanges Workflow 179
Disabling Validate Before Save 182
Table of Contents | v
7. Customizing Validations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
Overriding ValidateEntity in the DbContext 183
Considering Different Ways to Leverage ValidateEntity 187
Updating Data During SaveChanges 192
Overriding SaveChanges When Validation Occurs 193
Comparing ValidateEntity to SaveChanges for Custom Logic 197
Using the IDictionary Parameter of ValidateEntity 198
Controlling Which Entities Are Validated in ValidateEntity 200
8. Using DbContext in Advanced Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203
Moving Between ObjectContext and DbContext 203
Accessing ObjectContext Features from a DbContext 204
Adding DbContext into Existing .NET 4 Applications 205
Leveraging SQL Server Operators Exposed in SqlFunctions 208
Querying Derived Types with DbSet 209
Understanding the Interface Property Limitation 210
Considering Automated Testing with DbContext 210
Testing with DbSet 211
Exploring a Scenario That Unnecessarily Queries the Database 212
Reducing Database Hits in Testing with IDbSet 214
Creating an IDbSet Implementation 214
Abstracting BreakAwayContext for Tests 217
Reviewing the Implementation 221
Supplying Data to a FakeDbSet 221
Accessing the Database Directly from DbContext 222
Executing Queries with Database.SqlQuery and DbSet.SqlQuery 223
Tracking Results of SqlQuery 226
Executing Commands from the Database Class 226
Providing Multiple Targeted Contexts in Your Application 227
Reusing Classes, Configurations, and Validation Across Multiple
Contexts 227
Ensuring That All DbContexts Use a Single Database 231
Validating Relationship Constraints and Other Validations with Mul-
tiple Contexts 232
Getting Code First to Create Full BreakAwayContext Database 232
9. What’s Coming Next for Entity Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235
Understanding Entity Framework’s Version Numbers 235
Entity Framework 5.0 236
Enums 236
Spatial Data 236
Performance Improvements 236
Multiple Result Sets from Stored Procedures 237
vi | Table of Contents
Table Value Functions 237
Table of Contents | vii
Preface
Microsoft’s principal data access technology, ADO.NET Entity Framework, has had
two major releases as part of the .NET Framework. .NET 3.5 brought us the first version
of Entity Framework, which is covered in the first edition of Programming Entity
Framework (O’Reilly). In 2010, Microsoft .NET 4 was released, containing the next
versionofEntityFramework,referredtoasEntityFramework4.Thecompletelyrevised
second edition of Programming Entity Framework (O’Reilly) was dedicated to teaching
readers how to use this version of Entity Framework in Visual Studio 2010.
When .NET 4 was released, the Entity Framework team was already hard at work on
a new addition, called Code First, to provide an alternative way of building the Entity
Data Model that is core to Entity Framework. Rather than using a visual designer, Code
First allows you to create the model from your existing classes. At the same time, the
team devoted resources to making Entity Framework easier to use. They focused on
the most commonly used features and tasks in Entity Framework and built a new API
called the DbContext API.
This book is dedicated to teaching readers how to use the features of the DbContext
API. In addition to the DbContext class, you’ll find the DbSet class for performing set
operations, improved APIs for change tracking and handling concurrency conflicts, and
a Validation API that integrates with validation features already present in .NET.
In this book, you will learn how to query and update data using the new API, whether
you are working with individual objects or graphs of objects and their related data.
You’ll learn how to take advantage of the change tracking features and Validation.
You’ll find myriad samples and delve into taking advantage of advanced features pre-
sented by the API.
Audience
This book is designed for .NET developers who have experience with Visual Studio
and database management basics. Prior experience with Entity Framework is beneficial
but not required. The code samples in the book are written in C#, with some of these
ix
samples also expressed in Visual Basic. There are a number of online tools you can use
to convert snippets of C# into Visual Basic.
Contents of This Book
This book contains nine chapters.
Chapter 1, Introducing the DbContext API
This chapter provides a high-level, end-to-end overview of the DbContext API.
You’ll learn why the Entity Framework team decided to create the DbContext API
and how it makes the Entity Framework easier to use. You’ll find example code,
but there are no walkthroughs in this first chapter.
Chapter 2, Querying with DbContext
In this chapter you’ll learn about retrieving data from the database using Entity
Framework’s query capabilities. You’ll learn how to find an entity based on its key
and how to load all entities of a given type. You’ll learn how to use Language
Integrated Query (LINQ) to sort and filter data. This chapter also explores the
various strategies for loading related data.
Chapter 3, Adding, Changing, and Deleting Entities
Once you’ve learned how to query for data, this chapter will cover how to make
changes to that data and save those changes to the database. You’ll see how to add
new data as well as change and delete existing data. You’ll learn how Entity Frame-
work keeps track of changes as you make them and how it saves them using the
SaveChanges method.
Chapter 4, Working with Disconnected Entities Including N-Tier Applications
In this chapter, you’ll learn about using Entity Framework to persist changes that
were made to entities while they were not being managed by a context. This chal-
lenge is most common in N-Tier applications where a server component is re-
sponsible for retrieving data and returning it to a client application. The client
application then modifies this data and sends it back to the server to be saved.
You’lllearnaboutvariousapproachestosolvingthischallengeandhowtheChange
Tracker API can be used to implement them.
Chapter 5, Change Tracker API
The Change Tracker API is first introduced in Chapter 4 and this chapter is dedi-
cated to exploring the remaining functionality of the change tracker. You’ll learn
how to access the information that Entity Framework keeps about the state of your
entity instances. You’ll also learn about the operations that can be performed from
the Change Tracker API, including refreshing an entity from the database. This
chapter wraps up with some examples of how the Change Tracker API can be used
to solve some common application requirements.
x | Preface
Chapter 6, Validating with the Validation API
Chapter 6 introduces the new Validation API that integrates with the DbContext
and how it can be used to validate changes to your data before they are sent to the
database. This chapter covers how the Validation API makes use of the existing
validation functionality included in the .NET Framework. You’ll learn how vali-
dation is integrated into the SaveChanges pipeline and how you can also trigger
validation manually. You’ll learn how to set up validation rules and how to inspect
validation errors when your data violates these rules.
Chapter 7, Customizing Validations
This chapter explores some more advanced features of the Validation API, which
was introduced in Chapter 6. You’ll learn how to customize the logic used to val-
idate entities, including customizing the logic that determines which entities need
to be validated. These advanced techniques will allow you to write validation that
interacts with the context, which opens up more validation possibilities, such as
validating the uniqueness of a column. This chapter will also provide guidance
regarding the dangers of using the Validation API for tasks other than validation.
Chapter 8, Using DbContext in Advanced Scenarios
Chapter 8 is devoted to covering some advanced functionality that’s available in
the DbContext API. You’ll learn about techniques for unit testing and how to write
tests that don’t hit a database. You’ll also see how to bypass Entity Framework’s
query pipeline and interact directly with the database when the need arises. Should
your requirements exceed what is possible from the DbContext API, you’ll see how
to drop down to the underlying ObjectContext API. The chapter wraps up with a
look at creating smaller bounded contexts that allow you to interact with a subset
of your complete model.
Chapter 9, What’s Coming Next for Entity Framework
This book was written based on the features of the DbContext API available in the
EntityFramework4.3release.Atthetimeofwriting,thereareanumberofpreviews
available that demonstrate some of the features that the DbContext API will gain
in upcoming releases. This chapter shares available information about these future
releases.
Conventions Used in This Book
The following typographical conventions are used in this book:
Italic
Indicates new terms, URLs, email addresses, filenames, and file extensions.
Constant width
Used for program listings, as well as within paragraphs to refer to program elements
such as variable or function names, databases, data types, environment variables,
statements, and keywords.
Preface | xi
Constant width bold
Shows commands or other text that should be typed literally by the user.
Constant width italic
Shows text that should be replaced with user-supplied values or by values deter-
mined by context.
This icon signifies a tip, suggestion, or general note.
This icon indicates a warning or caution.
Using Code Examples
This book is here to help you get your job done. In general, you may use the code in
this book in your programs and documentation. You do not need to contact us for
permission unless you’re reproducing a significant portion of the code. For example,
writing a program that uses several chunks of code from this book does not require
permission. Selling or distributing a CD-ROM of examples from O’Reilly books does
require permission. Answering a question by citing this book and quoting example
code does not require permission. Incorporating a significant amount of example code
from this book into your product’s documentation does require permission.
We appreciate, but do not require, attribution. An attribution usually includes the title,
author, publisher, and ISBN. For example: “Programming Entity Framework: DbCon-
text by Julia Lerman and Rowan Miller (O’Reilly). Copyright 2012 Julia Lerman and
Rowan Miller, 978-1-449-31296-1.”
If you feel your use of code examples falls outside fair use or the permission given above,
feel free to contact us at permissions@oreilly.com.
Safari® Books Online
Safari Books Online (www.safaribooksonline.com) is an on-demand digital
library that delivers expert content in both book and video form from the
world’s leading authors in technology and business. Technology profes-
sionals, software developers, web designers, and business and creative
professionals use Safari Books Online as their primary resource for re-
search, problem solving, learning, and certification training.
xii | Preface
Safari Books Online offers a range of product mixes and pricing programs for organi-
zations, government agencies, and individuals. Subscribers have access to thousands
of books, training videos, and prepublication manuscripts in one fully searchable da-
tabasefrompublisherslikeO’ReillyMedia,PrenticeHallProfessional,Addison-Wesley
Professional, Microsoft Press, Sams, Que, Peachpit Press, Focal Press, Cisco Press, John
Wiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FT
Press, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, Course Tech-
nology, and dozens more. For more information about Safari Books Online, please visit
us online.
How to Contact Us
Please address comments and questions concerning this book to the publisher:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
800-998-9938 (in the United States or Canada)
707-829-0515 (international or local)
707-829-0104 (fax)
We have a web page for this book, where we list errata, examples, and any additional
information. You can access this page at:
http://shop.oreilly.com/product/0636920022237.do
To comment or ask technical questions about this book, send email to:
bookquestions@oreilly.com
For more information about our books, courses, conferences, and news, see our website
at http://www.oreilly.com.
Find us on Facebook: http://facebook.com/oreilly
Follow us on Twitter: http://twitter.com/oreillymedia
Watch us on YouTube: http://www.youtube.com/oreillymedia
Acknowledgments
We are grateful for the people who spent their precious free time reading through and
even trying the walkthroughs in this book and providing feedback. Thanks to Rowan’s
teammates, Arthur Vickers, Pawel Kadluczka, and Diego Vega, for their help in ensur-
ing our accuracy throughout this book. Roland Civet, Mikael Eliasson, and Daniel
Wertheim also provided invaluable feedback that helped us fine-tune our explanations
and our code.
Thanks to Microsoft for making it possible for Rowan to participate in this project.
Preface | xiii
Thanks once again to O’Reilly Media, especially our editors, Meghan Blanchette and
Rachel Roumeliotis, for their support, their copyediting, and their extreme patience as
many schedule conflicts delayed our promised deadlines.
xiv | Preface
CHAPTER 1
Introducing the DbContext API
Since its first release, the most critical element in Entity Framework has been the
ObjectContext. It is this class that allows us to interact with a database using a concep-
tual model. The context lets us express and execute queries, track changes to objects
and persist those changes back to the database. The ObjectContext class interacts with
other important Entity Framework classes such as the ObjectSet, which enables set
operations on our entities in memory, and ObjectQuery, which is the brains behind
executing queries. All of these classes are replete with features and functionality—some
of it complex and much of it only necessary for special cases. After two iterations of
Entity Framework (in .NET 3.5 SP1 and .NET 4) it was clear that developers were most
commonly using a subset of the features, and unfortunately, some of the tasks we
needed to do most frequently were difficult to discover and code.
Recognizing this, the Entity Framework team set out to make it easier for developers
to access the most frequently used patterns for working with objects within Entity
Framework. Their solution was a new set of classes that encapsulate this subset of
ObjectContext features. These new classes use the ObjectContext behind the scenes, but
developers can work with them without having to tangle with the ObjectContext unless
they need to specifically use some of the more advanced features. The new set of classes
was originally released as part of Entity Framework 4.1 (EF 4.1).
The prominent classes in this simplified API surface are the DbContext, DbSet, and
DbQuery. This entire package of new logic is referred to as the DbContext API. The new
API contains more than just the DbContext class, but it is the DbContext that orchestrates
all of the new features.
The DbContext API is available in the EntityFramework.dll assembly, which also con-
tains the logic that drives Entity Framework Code First. This assembly is separate
from .NET and is even deployed separately as the EntityFramework NuGet package.
A major portion of the Entity Framework is part of the .NET Framework (primarily
System.Data.Entity.dll). The components that are included in .NET are considered the
“core components” of Entity Framework. The DbContext API is completely dependent
on these core components of Entity Framework. The Entity Framework team has
1
indicated that they are working to move more of these core components out of .NET
and into the EntityFramework.dll assembly. This will allow them to deliver more fea-
tures between releases of the .NET Framework.
In Table 1-1, you can see a list of the high-level features and classes in the DbContext
API, how they relate to the API surface from Entity Framework 4 (EF4), their general
purpose, and their benefits.
Table 1-1. Overview of DbContext API features
DbContext
API feature
Relevant EF4
feature/class General purpose Benefit of DbContext API
DbContext ObjectContext Represent a session with the database. Provide
query, change tracking and save capabilities.
Exposes and simplifies most
commonly used features of Ob-
jectContext.
DbSet ObjectSet Providesetoperationsforentitytypes,suchasAdd,
AttachandRemove.InheritsfromDbQuerytoexpose
query capabilities.
Exposes and simplifies most
commonly used features of Ob-
jectSet.
DbQuery ObjectQuery Provide querying capabilities. The query functionality of
DbQueryisexposedonDbSet,so
you don’t have to interact with
DbQuery directly.
Change
Tracker API
ObjectCon-
text.ObjectSta-
teManager
Get access to change tracking information and op-
erations (e.g., original values, current values) man-
aged by the context.
Simpler and more intuitive API
surface.
Validation API n/a Provide automatic validation of data at the data
layer.ThisAPItakesadvantageofvalidationfeatures
already existing in .NET 4.
New to DbContext API.
Code First
Model
Building
n/a Readsclassesandcode-basedconfigurationstobuild
in-memorymodel,metadataandrelevantdatabase.
New to DbContext API.
Getting the DbContext API into Your Project
The DbContext API is not released as part of the .NET Framework. In order to be more
flexible (and frequent) with releasing new features to Code First and the DbContext
API, the Entity Framework team distributes EntityFramework.dll through Microsoft’s
NuGet distribution feature. NuGet allows you to add references to your .NET projects
by pulling the relevant DLLs directly into your project from the Web. A Visual Studio
extension called the Library Package Manager provides an easy way to pull the appro-
priate assembly from the Web into your projects. Figure 1-1 displays a screenshot of
the Library Package Manager being used to download and add the EntityFramework
NuGet package into a project.
2 | Chapter 1: Introducing the DbContext API
You can learn more about using NuGet and the Library Package Man-
ager at nuget.org.
At the time of this book’s publication (early 2012), the current version
of EntityFramework package is 4.3. Chapter 9 provides an overview of
what to expect in future versions.
Looking at Some Highlights of the DbContext API
DbContext API is mostly targeted at simplifying your interaction with Entity Frame-
work, both by reducing the number of methods and properties you need to wade
through and by providing simpler ways to access commonly used tasks. In previous
versions of Entity Framework, these tasks were often complicated to discover and code.
We have a few favorites that act as great ambassadors to the new API, which we’ll share
with you here. You’ll learn more about these as you work your way through the book.
The samples used in this chapter are for explanation purposes only and
not intended for you to perform in Visual Studio. Beginning with the
next chapter, you’ll find walkthroughs that you can follow in Visual
Studio.
Figure 1-1. Getting EntityFramework.dll from the Library Package Manager
Looking at Some Highlights of the DbContext API | 3
Let’s start by looking at how the DbContext API simplifies the context that we define
and work with. We’ll compare the ObjectContext and DbContext based context classes
from the model we’ll be using in this book, based on BreakAway Geek Adventure’s
business applications. We’ll expose queryable sets of People, Destinations, and Trips
based on a Person class, a Destination class, and a Trip class.
Example 1-1 shows a subset of the BreakAwayContext class used in Entity Framework
4, based on an ObjectContext. It wraps up some known types into ObjectSets, which
you can query against.
Example 1-1. BreakAwayContext that inherits from ObjectContext
public class BreakAwayContext : ObjectContext
{
private ObjectSet<Person> _ people;
private ObjectSet<Destination> _destinations;
private ObjectSet<Trip> _trips;
public ObjectSet<Person> People
{
get { return _people ?? (_people = CreateObjectSet<Person>("People")); }
}
public ObjectSet< Destination > Contacts
{
get { return _ destinations?? (_destinations =
CreateObjectSet< Destination >("Destinations")); }
}
public ObjectSet<Trip> Trips
{
get { return _ trips?? (_trips = CreateObjectSet<Trip>("Trips")); }
}
}
Example 1-2 shows the same context and sets using a DbContext and DbSets instead.
Already you can see a big improvement. You can use automatic properties with DbSet
(that’s the simplified get;set; pattern), something you can’t do with ObjectSet. This
makes for much cleaner code right out of the gate. There is a CreateDbSet method that’s
relative to CreateObjectSet, but you aren’t required to use it for the purpose of creating
a DbSet when you have no other logic to apply.
Example 1-2. BreakAwayContext inheriting from DbContext
public class BreakAwayContext : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Destination> Destinations { get; set; }
public DbSet<Trip> Trips { get; set; }
}
4 | Chapter 1: Introducing the DbContext API
Reducing and Simplifying Ways to Work with a Set
In Entity Framework 4, there are a number of tasks that you can achieve from both
ObjectContext and ObjectSet. For example, when adding an object instance to a set,
you can use ObjectContext.AddObject or ObjectSet.AddObject. When adding an object
into the context, the context needs to know which set it belongs to. With
ObjectContext.AddObject, you must specify the set using a string, for example:
context.AddObject("Trips", newTrip);
When ObjectSet was introduced in Entity Framework 4, it came with its own
AddObject method. This path already provides knowledge of the set so you can simply
pass in the object:
context.Trips.AddObject(newTrip);
With this new method available, the only reason ObjectContext.AddObject continued
to exist in Entity Framework 4 was for backward compatibility with earlier versions.
But developers who were not aware of this reason were confused by the fact that there
were two options.
Because the DbContext API is new, we don’t have to worry about backward compat-
ibility, so the DbContext does not have a direct method for adding an object. Addition-
ally, rather than providing the clunky AddObject method in DbSet, the method name is
now simply Add:
context.Trips.Add(newTrip);
ObjectContext also has AttachObject and DeleteObject. DbContext does not have these
methods either. DbSet has Attach and Remove, which are equivalent to ObjectSet’s
Attach and Delete Object. You’ll learn more about interacting with DbSet beginning in
Chapter 2.
Retrieving an Entity Using ID with DbSet.Find
One task that developers perform frequently is retrieving an entity by providing its key
value. For example, you may have access to the PersonId value of a Person in a variable
named _personId and would like to retrieve the relevant person data.
Typically you would construct and execute a LINQ to Entities query. Here’s a query
that uses the SingleOrDefault LINQ method to filter on PersonId when executing a
query on context.People:
context.People.SingleOrDefault(p => p.PersonId == _personId)
Have you written that code so often that you finally wrote a wrapper method so you
could pass the key value in and it would execute the LINQ query for you? Yeah, us too.
Now DbSet has that shortcut built in with the Find method, which will return an entity
whose key property matches the value passed into the method:
context.People.Find(_personId)
Looking at Some Highlights of the DbContext API | 5
Find has another benefit. While the SingleOrDefault query above will always query the
database, Find will first check to see if that particular person is already in memory,
being tracked by the context. If so, that’s what will be returned. If not, it will make the
trip to the database. Under the covers, DbContext is executing logic on ObjectContext
to perform the necessary tasks. You’ll learn more about DbSet.Find in Chapter 2.
Avoiding Trolling Around the Guts of Entity Framework
These are just a few examples of how much more natural it is to work with the DbCon-
text API than the ObjectContext API. If you read Programming Entity Framework, 2e,
you might be familiar with the many extension methods that Julie created and com-
bined to simplify retrieving instances of objects that are being tracked by the context
from the ObjectStateManager. One simple property, DbSet.Local, now performs that
same task. In fact, thanks to the new Change Tracker API, there’s no need to dig into
the ObjectStateManager. It’s not even part of the DbContext API. Instead you can use
DbContext.Entry or DbContext.Entries to find and even change the information being
tracked by the context. You’ll learn more about these methods in Chapter 5.
Working with the BreakAway Model
This book follows the model built around the BreakAway Geek Adventures company
in the book Programming Entity Framework: Code First (O’Reilly). Even though the
examples in this book use a model defined with Code First, the concepts apply just as
well to a model built using the designer.
Getting the Sample Solution
If you want to follow along the book’s examples, you’ll need to download the starting
solution from the download page of the book’s website at http://learnentityframework
.com/downloads. In the solution you’ll find three projects:
1. The Model project contains the domain classes, which are configured using Data
Annotations.
2. The DataAccess project contains the BreakAwayContext class that derives from
DbContext.
3. The BreakAwayConsole project is a console application where you can add and
execute methods as we explore the many capabilities of the DbContext API.
When using Code First you begin with your classes. Code First uses convention to infer
what the schema of the relevant database looks like and how Entity Framework can
translate from your classes to that database. Code First’s conventions do not always
align with your reality, however, so you can tweak how Code First maps your classes
to the database by performing additional configuration. There are two ways to apply
this additional configuration. One is by adding attributes to your classes and their
6 | Chapter 1: Introducing the DbContext API
properties (called Data Annotations) and the other is by using Code First’s Fluent API.
In the Code First book, we showed you how to use both features and built up two
versions of the BreakAway model—one that uses Data Annotations to configure the
mappings and the other using the Fluent API.
The examples in this book and the sample download are based on the version of the
model that uses Data Annotations. For example, the first class you’ll encounter in
Chapter 2 is the Destination class, which is displayed here in Example 1-3.
Example 1-3. A class using Data Annotations to specify Code First configuration
[Table("Locations", Schema = "baga")]
public class Destination
{
public Destination()
{
this.Lodgings = new List<Lodging>();
}
[Column("LocationID")]
public int DestinationId { get; set; }
[Required, Column("LocationName")]
[MaxLength(200)]
public string Name { get; set; }
public string Country { get; set; }
[MaxLength(500)]
public string Description { get; set; }
[Column(TypeName = "image")]
public byte[] Photo { get; set; }
public string TravelWarnings { get; set; }
public string ClimateInfo { get; set; }
public List<Lodging> Lodgings { get; set; }
}
The Destination class has a number of Data Annotations. It begins with a Table at-
tribute indicating that the Destination class will map to a database table named Loca
tions which has the schema baga. Without this annotation, Code First would presume
the table name is the plural of Destination (Destinations), in the default dbo schema.
The DestinationId property is configured to map to a column in the table named
LocationId and the Name column to one called LocationName, with a max length of 200.
The System.Data.SqlClient provider will default to specifying that the LocationName
column is an nvarchar(200). Another annotation ensures that Code First understands
that the Photo property maps to a column whose type is image.
The BreakAway context class inherits from System.Data.Entity.DbContext, the central
class of the DbContext API. It contains properties that reflect sets of the various model
classes contained in the solutions. For example a property named Destinations returns
a queryable set of Destination types. The queryable set comes in the form of a DbSet
class—another piece of the DbContext API. Example 1-4 gives you a sampling of
Working with the BreakAway Model | 7
properties in the BreakAwayContext class, which you’ll see more of beginning with the
next chapter.
Example 1-4. A context class exposing three DbSets that wrap domain classes
public class BreakAwayContext : DbContext
{
public DbSet<Destination> Destinations { get; set; }
public DbSet<Lodging> Lodgings { get; set; }
public DbSet<Trip> Trips { get; set; }
}
Code First can either create a database for you or be used to map to an existing database.
By default, Code First will create a database for you on your local SQL Express instance,
using the namespace-qualified context name as the name for the database. For the sake
of simplicity, the examples in this book will let Code First create a database automat-
ically. After running some of the sample code, you will find a DataAccess.BreakAway
Context database on your local SQL Express instance.
You can learn much more about Code First, its configurations, and its
database interactions in Programming Entity Framework: Code First.
Getting DbContext from an EDMX Model
Although the book samples use Code First, you may not be using Code First to describe
the model in your applications. If, instead, you are using the Entity Data Model De-
signer and want to take advantage of the DbContext API, there’s an easy way to do
that. Visual Studio uses the Text Template Transformation Toolkit (T4) generator to
generate the default ObjectContext and classes from an EDMX file. The generator uses
a default template, which is designed to create class fields in a particular way. With the
default template, each entity in the model becomes a class that inherits from EntityOb
ject and a separate class is generated to manage the entities that inherits from Object
Context.
Microsoft provides alternative templates that you can use to generate POCO classes
and a DbContext-based context from the EDMX. These are available online and can
easily be selected from within the Entity Data Model Designer:
1. Open your EDMX file in the Entity Data Model designer.
2. Right-click on the model background and select “Add Code Generation Item…”
as shown in Figure 1-2.
3. In the Add New Item window, select “Online Templates” from the left menu and
then search for “DbContext.” Select the DbContext Generator template from the
search results, enter a name, and click “Add” (Figure 1-3).
8 | Chapter 1: Introducing the DbContext API
As a result, two templates will be added to your project. One is a context template
(Model.Context.tt in the sample shown in Figure 1-4), which generates a class that
inherits from DbContext, shown in Example 1-5.
Figure 1-2. Adding a new T4 template code generation item from the model’s context menu
Figure 1-3. Selecting the DbContext Generator template
Working with the BreakAway Model | 9
Figure 1-4. Project with .tt template files and their code-generated .cs files
Example 1-5. Generated BAEntities class inheriting from DbContext
public partial class BAEntities : DbContext
{
public BAEntities()
: base("name=BAEntities")
{
this.Configuration.LazyLoadingEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Activity> Activities { get; set; }
public DbSet<Contact> Contacts { get; set; }
public DbSet<CustomerType> CustomerTypes { get; set; }
public DbSet<Equipment> EquipmentSet { get; set; }
public DbSet<Trip> Trips { get; set; }
public DbSet<Destination> Destinations { get; set; }
public DbSet<Lodging> Lodgings { get; set; }
10 | Chapter 1: Introducing the DbContext API
public DbSet<Payment> Payments { get; set; }
}
The second template (also shown in Figure 1-4), here called Model.tt, is the one that
generatesPOCOclassesforeachoftheentitiesinyourEDMXmodel.Asyousawabove,
the context class exposes each of these POCO types in a DbSet.
Using this template, you can take advantage of an existing visual model and still benefit
from the DbContext API, which you’ll be learning about in this book.
Ensuring DbContext Instances Get Disposed
A DbContext (and its underlying ObjectContext) are responsible for managing and
tracking changes to instances of the classes in its model. These classes are also respon-
sible for managing a connection to the database. It’s important to ensure that any re-
sources used to perform these operations are cleaned up when the DbContext instance
is no longer needed. DbContext implements the standard .NET IDisposable interface,
which includes a Dispose method that will release any such resources.
The examples in this book will make use of the using pattern, which will take care of
disposing the context when the using block completes (Example 1-6). If your applica-
tion doesn’t make use of the using pattern, ensure that the Dispose method is called on
any DbContext instances when they are no longer needed.
Example 1-6. Instantiating and disposing a context with the using pattern
public static List<Destination> GetDestinations()
{
using (var context = new BreakAwayContext())
{
var query= from d in context.Destinations
orderby d.Name
select d;
return query.ToList();
}
}
Ensuring DbContext Instances Get Disposed | 11
CHAPTER 2
Querying with DbContext
There are two things that almost every application that accesses a database has in com-
mon: the need to retrieve data from the database and to save changes to that data back
into the database. Over the next two chapters you will see how the DbContext API
makes it easy to achieve these tasks using the Entity Framework. The focus of this
chapter will be on retrieving data from the database.
One of the great benefits of using an Object Relational Mapper (ORM), such as Entity
Framework, is that once we have set up the mapping, we can interact with our data in
terms of the objects and properties that make up our model, rather than tables and
columns. When querying for objects, this means we no longer need to know how to
write queries using the SQL syntax of our database.
Writing Queries with LINQ to Entities
Entity Framework queries are written using a .NET Framework feature known as Lan-
guage Integrated Query, or LINQ for short. As the name suggests, LINQ is tightly
integrated with the .NET programming experience and provides a strongly typed query
language over your model. Strongly typed simply means that the query is defined using
the classes and properties that make up your model. This provides a number of benefits
such as compile-time checks to ensure your queries are valid and the ability to provide
IntelliSense as you write your queries.
LINQ is a general query framework and isn’t specific to Entity Framework, or even
databases for that matter. A LINQ Provider is responsible for taking your LINQ query,
translating it into a query against the data, and then returning results. For Entity
Framework this provider is known as LINQ to Entities and is responsible for taking
your LINQ query and translating it into a SQL query against the database you are
targeting. The information you supplied to Entity Framework about the shape of your
model and how it maps to the database is used to perform this translation. Once the
query returns, Entity Framework is responsible for copying the data into instances of
the classes that make up your model.
13
The capabilities of LINQ and its use within Entity Framework are beyond the scope of
this book. This chapter will provide an overview to help you get up and running with
queries using DbContext, but is not an exhaustive query guide. Programming Entity
Framework, 2e, provides a much more in-depth look at the query capabilities of Entity
Framework, not only in Chapter 3 and Chapter 4, which are dedicated to querying, but
throughout the book.
InadditiontoLINQ,EntityFrameworkalsosupportsatext-basedquery
language known as Entity SQL, or ESQL for short. ESQL is typically
used in more advanced scenarios where queries need to be dynamically
constructed at runtime. Because ESQL is text-based, it is also useful in
scenarios where the application needs to build a query against a model
that isn’t known until runtime. Given that ESQL is less commonly used,
it is not exposed directly on the DbContext API. If your application
requires the use of ESQL, you will need to access the ObjectContext API
using the IObjectContextAdapter interface.
To follow along with the examples in this book you will need a Visual Studio solution
containing a console application that references the BAGA model built in Programming
Entity Framework: Code First. You can download a prebuilt solution from http://lear
nentityframework.com/downloads. This prebuilt solution also includes a database ini-
tializer that will reset the database and insert some seed data into the database each
time you run the application. The seed data is used in the examples throughout this
book.
Code First Migrations
Entity Framework 4.3 includes a new Code First Migrations feature that allows you to
incrementally evolve the database schema as your model changes over time. For most
developers, this is a big improvement over the database initializer options from the 4.1
and 4.2 releases that required you to manually update the database or drop and recreate
it when your model changed.
The prebuilt solution still makes use of the DropCreateDatabaseAlways initializer rather
than using Code First Migrations. This allows us to ensure the database is reset to a
well-known state before you run each example in this book.
You can learn more about Code First Migrations at http://blogs.msdn.com/b/adonet/
archive/2012/02/09/ef-4-3-released.aspx.
The Model project of the prebuilt solution contains classes that make up the BAGA
domain model. The BAGA model includes a Destination class (Example 2-1) that rep-
resents all the wonderful places that our intrepid travelers can venture to.
14 | Chapter 2: Querying with DbContext
Example 2-1. Destination class as listed in download solution
[Table("Locations", Schema = "baga")]
public class Destination
{
public Destination()
{
this.Lodgings = new List<Lodging>();
}
[Column("LocationID")]
public int DestinationId { get; set; }
[Required, Column("LocationName")]
[MaxLength(200)]
public string Name { get; set; }
public string Country { get; set; }
[MaxLength(500)]
public string Description { get; set; }
[Column(TypeName = "image")]
public byte[] Photo { get; set; }
public string TravelWarnings { get; set; }
public string ClimateInfo { get; set; }
public List<Lodging> Lodgings { get; set; }
}
The BAGA model also includes a Lodging class (Example 2-2) that represents the ac-
commodation that is available at the various Destinations.
Example 2-2. Lodging class as listed in download solution
public class Lodging
{
public int LodgingId { get; set; }
[Required]
[MaxLength(200)]
[MinLength(10)]
public string Name { get; set; }
public string Owner { get; set; }
public decimal MilesFromNearestAirport { get; set; }
[Column("destination_id")]
public int DestinationId { get; set; }
public Destination Destination { get; set; }
public List<InternetSpecial> InternetSpecials { get; set; }
public Nullable<int> PrimaryContactId { get; set; }
[InverseProperty("PrimaryContactFor")]
[ForeignKey("PrimaryContactId")]
public Person PrimaryContact { get; set; }
public Nullable<int> SecondaryContactId { get; set; }
[InverseProperty("SecondaryContactFor")]
[ForeignKey("SecondaryContactId")]
public Person SecondaryContact { get; set; }
}
Writing Queries with LINQ to Entities | 15
The Destination and Lodging classes will be used extensively for the examples through-
out this book. To perform data access using these classes you will be using the BreakA
wayContext from the DataAccess project. The project contains additional classes that
are represented in BreakAwayContext as well as the Lodgings and Destinations. We’ll be
using Code First for the examples in this book, but the techniques you will learn apply
to any context that derives from DbContext. This includes contexts created using the
Model First or Database First workflows.
Example 2-3. BreakAwayContext class as listed in download solution
public class BreakAwayContext : DbContext
{
public DbSet<Destination> Destinations { get; set; }
public DbSet<Lodging> Lodgings { get; set; }
public DbSet<Trip> Trips { get; set; }
public DbSet<Person> People { get; set; }
public DbSet<Reservation> Reservations { get; set; }
public DbSet<Payment> Payments { get; set; }
public DbSet<Activity> Activities { get; set; }
}
Querying All the Data from a Set
Arguably the simplest query you can write is one that fetches all the data for a given
entity type. This is the equivalent of a SELECT * FROM mytable query in SQL. Fortunately
you don’t need to know SQL, because Entity Framework will take care of translating
LINQ queries into SQL for you.
Getting all the data from a set doesn’t require you to really write a query. You can simply
iterate over the contents of any given DbSet and Entity Framework will send a query to
the database to find all the data in that set. Let’s add a PrintAllDestinations method
to our console application that iterates over the Destinations set defined in our Break
AwayContext and prints out the name of each Destination (Example 2-4).
Example 2-4. Query for all destinations
private static void PrintAllDestinations()
{
using (var context = new BreakAwayContext())
{
foreach (var destination in context.Destinations)
{
Console.WriteLine(destination.Name);
}
}
}
16 | Chapter 2: Querying with DbContext
When you debug the application, the console window will close when
the application has finished executing, which may prevent you from
inspectingtheoutput.Youcanputabreakpointattheendofthemethod
for debugging. Alternatively, you can run without debugging (CTRL +
F5), in which case Visual Studio will ensure that the console window
remains open after the program has finished executing.
If you update the Main method to call this new PrintAllDestinations method and run
the application, you will see that the name of eachDestination in the database is printed
to the console:
Grand Canyon
Hawaii
Wine Glass Bay
Great Barrier Reef
As the code began iterating over the contents of the Destinations set, Entity Framework
issued a SQL query against the database to load the required data:
SELECT
[Extent1].[LocationID] AS [LocationID],
[Extent1].[LocationName] AS [LocationName],
[Extent1].[Country] AS [Country],
[Extent1].[Description] AS [Description],
[Extent1].[Photo] AS [Photo]
FROM [baga].[Locations] AS [Extent1]
The SQL may not look like the SQL you would have written. This is because Entity
Framework has a generic query building algorithm that not only caters to this very
simple query, but also for much more complex scenarios.
The query is sent to the database when the first result is requested by the application:
that’s during the first iteration of the foreach loop. Entity Framework doesn’t pull back
all the data at once, though. The query remains active and the results are read from the
database as they are needed. By the time the foreach loop is completed, all the results
have been read from the database.
One important thing to note is that Entity Framework will query the database every
time you trigger an iteration over the contents of a DbSet. This has performance impli-
cations if you are continually querying the database for the same data. To avoid this,
you can use a LINQ operator such as ToList to copy the results into a list. You can then
iterate over the contents of this list multiple times without causing multiple trips to the
database. Example 2-5 introduces a PrintAllDestinationsTwice method that demon-
strates this approach.
Example 2-5. Iterating all Destinations twice with one database query
private static void PrintAllDestinationsTwice()
{
using (var context = new BreakAwayContext())
{
Querying All the Data from a Set | 17
var allDestinations = context.Destinations.ToList();
foreach (var destination in allDestinations)
{
Console.WriteLine(destination.Name);
}
foreach (var destination in allDestinations)
{
Console.WriteLine(destination.Name);
}
}
}
Because a query is sent to the database to find the items in a DbSet, iterating a DbSet
will only contain items that exist in the database. Any objects that are sitting in memory
waiting to be saved to the database will not be returned. To ensure added objects are
included you can use the techniques described in “Querying Local Data”
on page 24.
Using LINQ for Sorting, Filtering, and More
While this chapter will not be an exhaustive list of everything you can do with LINQ
and Entity Framework, let’s take a look at the patterns used to achieve some common
query tasks. Let’s say you want to print out the names of Destinations again, but this
time you want them ordered alphabetically by Name. Add a new PrintAllDestinations
Sorted method that uses a LINQ query to perform this sort (Example 2-6).
Example 2-6. Query for destinations sorted by name
private static void PrintAllDestinationsSorted()
{
using (var context = new BreakAwayContext())
{
var query = from d in context.Destinations
orderby d.Name
select d;
foreach (var destination in query)
{
Console.WriteLine(destination.Name);
}
}
}
The above code uses LINQ to create a query and then iterates the results of the query
and displays the name of each destination. The query is expressed using a syntax that
looks a little bit like SQL. You start by telling it what you want to select from (in our
case, the Destinations set on our context). You give the set a name so that you can refer
to it throughout the rest of the query (in our case that name is d). Following this, you
18 | Chapter 2: Querying with DbContext
use operators such as orderby, groupby, and where to define the query. Finally you spec-
ify what you want returned using the select operator. In our case we want the actual
Destination objectsreturned,sowespecifythenamethatwegavethesetinthefirstline.
Remember that Entity Framework won’t execute the query against the database until
it needs the first result. During the first iteration of the foreach loop, the query is sent
to the database. The query remains active and each result is read from the database as
it is needed by the application. LINQ also includes methods that will copy the results
of a query into a collection. For example, ToList can be called on a query to copy the
results into a new List<T>. Calling a method such as this will cause all the results to be
retrieved from the database and be copied into the new List<T>.
The code shown in Example 2-6 uses the LINQ query syntax to express the query.
While most people find this the easiest to understand, there is an alternate method
syntax that can be used if you prefer. Example 2-7 shows the same query expressed
using method syntax.
Example 2-7. LINQ method syntax in C#
var query = context.Destinations
.OrderBy(d => d.Name);
The method syntax makes use of lambda expressions to define the query. The LINQ
methods are strongly typed, which gives you IntelliSense and compile-time checking
for the lambda expressions you write. For example, in the OrderBy method we are using
a lambda expression to specify that we want to order by the Name property. You start a
lambda expression by giving a name to the thing you are operating on; this forms the
left side of the expression. In our case we are operating on a Destination and we have
chosen to call it d. Then, on the right side of the expression, you specify the body of
the expression. In our case we just want to identify the Name property.
C# uses the lambda sign (=>) to separate the left and right sides of the expression.
VB.NET uses the Function keyword followed by brackets to identify the left side of the
expression. Example 2-8 shows the same query written in VB.NET using the method
syntax.
Example 2-8. LINQ method syntax in VB.NET
context.Destinations.OrderBy(Function(d) d.Name)
Another common task is to filter the results of a query. For example, we may only want
Destinations from Australia. Add the PrintAustralianDestinations method shown in
Example 2-9.
Example 2-9. Query for Australian destinations
private static void PrintAustralianDestinations()
{
using (var context = new BreakAwayContext())
{
Using LINQ for Sorting, Filtering, and More | 19
var query = from d in context.Destinations
where d.Country == "Australia"
select d;
foreach (var destination in query)
{
Console.WriteLine(destination.Name);
}
}
}
This code looks very similar to the PrintAllDestinationsSorted we saw in Exam-
ple 2-6, except we are using thewhere operator instead of orderby. You can also combine
these operators. Example 2-10 shows how to query for Australian Destinations sorted
by name.
Example 2-10. Query combining filter and sort
var query = from d in context.Destinations
where d.Country == "Australia"
orderby d.Name
select d;
Operators can also be combined in the method syntax. The same query from Exam-
ple 2-10 is shown using method syntax in Example 2-11.
Example 2-11. Method syntax for combining filter and sort
var query = context.Destinations
.Where(d => d.Country == "Australia")
.OrderBy(d => d.Name);
So far our queries have returned collections of entities from our model, but this may
not always be the case. In fact, we have been returning complete Destination objects
when we really only need the name. You can use projection to create a query that selects
from a set of entities in your model but returns results that are of a different type. For
example, you can use projection to create a query that selects from a set of entities type
but only returns a subset of the properties of that entity. It’s called projection because
you are projecting data from the shape of the source that you are selecting from onto
the shape of the result set you want.
In our case we want to project a query about Destinations into a result set that just has
a string representing the destination’s name. Example 2-12 adds a PrintDestination
NameOnly method that shows how we use the select section of our query to specify what
we want the result set to contain.
Example 2-12. Querying for just the Destination name
private static void PrintDestinationNameOnly()
{
using (var context = new BreakAwayContext())
{
20 | Chapter 2: Querying with DbContext
var query = from d in context.Destinations
where d.Country == "Australia"
orderby d.Name
select d.Name;
foreach (var name in query)
{
Console.WriteLine(name);
}
}
}
Example 2-13 shows how this same query can be written using method syntax by mak-
ing use of the Select method.
Example 2-13. Method syntax for projection
var query = context.Destinations
.Where(d => d.Country == "Australia")
.OrderBy(d => d.Name)
.Select(d => d.Name);
LINQ is a powerful query language and this section has just grazed the surface of its
capabilities. Programming Entity Framework, 2e, contains a much deeper look into
using LINQ with the Entity Framework. There are also more example queries available
in the Entity Framework MSDN documentation: http://msdn.microsoft.com/en-us/li
brary/bb399367.aspx.
Finding a Single Object
So far you’ve seen queries that return a collection of entities, but sometimes you will
want to run a query that just returns a single object. The most common scenario for
querying for a single object is to find the object with a given key. The DbContext API
makes this very simple by exposing a Find method on DbSet. Find accepts the value to
be searched for and will return the corresponding object if it is found. If there is no
entity with the provided key, Find will return null.
One of the great things about Find is that it doesn’t unnecessarily query the database.
It’s also capable of finding newly added objects that haven’t yet been saved to the
database. Find uses a simple set of rules to locate the object (in order of precedence):
1. Look in memory for an existing entity that has been loaded from the database or
attached to the context (you’ll learn more about attaching objects in Chapter 4).
2. Look at added objects that have not yet been saved to the database.
3. Look in the database for entities that have not yet been loaded into memory.
To see this behavior, add the FindDestination method shown in Example 2-14. This
method accepts an ID from the user and then attempts to locate the Destination with
the specified ID.
Finding a Single Object | 21
Example 2-14. Using Find to locate a Destination
private static void FindDestination()
{
Console.Write("Enter id of Destination to find: ");
var id = int.Parse(Console.ReadLine());
using (var context = new BreakAwayContext())
{
var destination = context.Destinations.Find(id);
if (destination == null)
{
Console.WriteLine("Destination not found!");
}
else
{
Console.WriteLine(destination.Name);
}
}
}
The code above uses the Find method to look up the Destination with the specified ID.
If one is found, it prints out the name of the destination. If Find returns null, indicating
there is no Destination with the specified ID, an error message is displayed to the user.
Find with Composite Keys
Entity Framework supports entities that have composite keys, that is, entities where the
key is made up of two or more properties. For example, you may have a Passport entity
that uses a combination of IssuingCountry and PassportNumber as its key. To locate
entities with a composite key you supply each of the key values to Find:
context.Passports.Find("USA", "123456789")
The key values must be supplied in the same order that they appear in the model. If
you are using Model First or Database First, this is the order that they appear in the
designer. When composite keys are used, Code First requires you to specify an order
for them. You can use the Column annotation with the Order parameter to specify the
order. If you are using the Fluent API, a HasKey call is required; the order of the key
properties is the order they appear in the body of the HasKey call.
There may be times when you want to query for a single object but are not able to use
Find. These could include wanting to query by something other than the key or wanting
to include related data in the query (as described in “Eager Loading” on page 33). To
do this, you will need to create a standard LINQ query and then use the Single method
to get a single object as the result.
Let’s say we want to locate the Destination that has the name Great Barrier Reef.
Name isn’t the key of Destination but we know there is, and only ever will be, one Great
Barrier Reef. Example 2-10 introduces a FindGreatBarrierReef method that will locate
this single Destination.
22 | Chapter 2: Querying with DbContext
Example 2-15. Query for single entity based on name
private static void FindGreatBarrierReef()
{
using (var context = new BreakAwayContext())
{
var query = from d in context.Destinations
where d.Name == "Great Barrier Reef"
select d;
var reef = query.Single();
Console.WriteLine(reef.Description);
}
}
The LINQ query looks the same as any other query that filters based on name. We then
use the Single method to let Entity Framework know that we expect a single result. If
the query returns no results, or more than one result, an exception will be thrown. If
there are potentially no matches, you can use the SingleOrDefault method, which will
return null if no results are found. Example 2-16 shows the FindGreatBarrierReef
method updated to account for the fact it may not exist in the database.
Example 2-16. Query for single entity that may not exist
private static void FindGreatBarrierReef()
{
using (var context = new BreakAwayContext())
{
var query = from d in context.Destinations
where d.Name == "Great Barrier Reef"
select d;
var reef = query.SingleOrDefault();
if (reef == null)
{
Console.WriteLine("Can't find the reef!");
}
else
{
Console.WriteLine(reef.Description);
}
}
}
SingleOrDefault uses the same database query that Find uses when it looks for entities
in the database. The SQL selects the TOP two results so that it can ensure there is only
one match:
SELECT TOP (2)
[Extent1].[LocationID] AS [LocationID],
[Extent1].[LocationName] AS [LocationName],
[Extent1].[Country] AS [Country],
Finding a Single Object | 23
[Extent1].[Description] AS [Description],
[Extent1].[Photo] AS [Photo],
[Extent1].[TravelWarnings] AS [TravelWarnings],
[Extent1].[ClimateInfo] AS [ClimateInfo]
FROM [baga].[Locations] AS [Extent1]
WHERE N'Great Barrier Reef' = [Extent1].[LocationName]
If two rows are found, Single and SingleOrDefault will throw because there is not a
single result. If you just want the first result, and aren’t concerned if there is more than
one result, you can use First or FirstOrDefault.
One important thing to remember is that LINQ queries against a DbSet always send a
query to the database to find the data. So, if the Great Barrier Reef was a newly added
Destination that hadn’t been saved to the database yet, the queries in Example 2-15
and Example 2-16 won’t be able to locate it. To look for newly added entities, you
would also need to query the in-memory data using the techniques shown in “Querying
Local Data” on page 24.
Querying Local Data
So far you’ve used LINQ to query a DbSet directly, which always results in a SQL query
being sent to the database to load the data. You’ve also used the Find method, which
will look for in-memory data before querying that database. Find will only query based
on the key property though, and there may be times when you want to use a more
complex query against data that is already in memory and being tracked by your
DbContext.
One of the reasons you may want to do this is to avoid sending multiple queries to the
database when you know that all the data you need is already loaded into memory.
Back in Example 2-5, we saw one way to do this was to use ToList to copy the results
of a query into a list. While this works well if we are using the data within the same
block of code, things get a little messy if we need to start passing that list around our
application. For example, we might want to load all Destinations from the database
when our application loads. Different areas of our application are then going to want
to run different queries against that data. In some places we might want to display all
Destinations, in others we might want to sort by Name, and in others we might want
to filter by Country. Rather than passing around a list of Destination objects, we can
take advantage of the fact that our context is tracking all the instances and query its
local data.
Another reason may be that you want the results to include newly added data, which
doesn’t yet exist in the database. Using ToList on a LINQ query against a DbSet will
always send a query to the database. This means that any new objects that don’t yet
exist in the database won’t be included in the results. Local queries, however, will
include newly created objects in the results.
24 | Chapter 2: Querying with DbContext
The in-memory data for a DbSet is available via the Local property. Local will return all
the data that has been loaded from the database plus any newly added data. Any data
that has been marked as deleted but hasn’t been deleted from the database yet will be
filtered out for you. More information on how entities get into these different states is
available in Chapter 3.
Let’s start with the very simple task of finding out how many Destinations are in mem-
ory and available to be queried. Go ahead and add the GetLocalDestinationCount
method, as shown in Example 2-17.
Example 2-17. Checking how many Destinations are in-memory
private static void GetLocalDestinationCount()
{
using (var context = new BreakAwayContext())
{
var count = context.Destinations.Local.Count;
Console.WriteLine("Destinations in memory: {0}", count);
}
}
The code accesses the Local property of the Destinations set that we created on our
BreakAwayContext. Rather than running a query, we simply store the count in a variable
and then print it to the console. If you run the application you will see that the count
is zero:
Destinations in memory: 0
We’re getting a zero count because we haven’t run any queries to load Destinations
from the database, and we haven’t added any new Destination objects either. Let’s
update the GetLocalDestinationCount method to query some data from the database
before getting the local count (Example 2-18).
Example 2-18. Checking in-memory data after a query
private static void GetLocalDestinationCount()
{
using (var context = new BreakAwayContext())
{
foreach (var destination in context.Destinations)
{
Console.WriteLine(destination.Name);
}
var count = context.Destinations.Local.Count;
Console.WriteLine("Destinations in memory: {0}", count);
}
}
This new code iterates over the Destinations set, causing the data to be loaded from
the database. Because the data is loaded when we get the count from theLocal property,
we now see a nonzero result when we run the application:
Querying Local Data | 25
Grand Canyon
Hawaii
Wine Glass Bay
Great Barrier Reef
Destinations in memory: 4
Using the Load Method to Bring Data into Memory
Iterating over the contents of a DbSet with a foreach loop is one way to get all the data
into memory, but it’s a little inefficient to do that just for the sake of loading data. It’s
also a little unclear what the intent of the code is, especially if the iteration code doesn’t
directly precede the local query.
Fortunately the DbContext API includes a Load method, which can be used on a
DbSet to pull all the data from the database into memory. Go ahead and add the GetLo
calDestinationCountWithLoad method (Example 2-19) that uses Load on the Destina
tions set and then prints out the count of in-memory Destinations.
Example 2-19. Using the Load to bring data into memory
private static void GetLocalDestinationCountWithLoad()
{
using (var context = new BreakAwayContext())
{
context.Destinations.Load();
var count = context.Destinations.Local.Count;
Console.WriteLine("Destinations in memory: {0}", count);
}
}
Compare this code with the GetLocalDestinationCount method we wrote back in Ex-
ample 2-18. This updated code makes it much clearer that our intent is to load the
contents of the Destinations set and then query the in-memory data.
Load is actually an extension method on IQueryable<T> and is defined in
the System.Data.Entity namespace. If you want to use Load, you will
need to have this namespace imported.
Because Load is an extension method on IQueryable<T>, we can also use it to load the
results of a LINQ query into memory, rather than the entire contents of a set. For
example, let’s say we only wanted to load Australian Destinations into memory and
then run a few local queries on that subset of data. Let’s add the LoadAustralianDesti
nations method shown in Example 2-20.
Example 2-20. Loading results of a LINQ query into memory
private static void LoadAustralianDestinations()
{
26 | Chapter 2: Querying with DbContext
using (var context = new BreakAwayContext())
{
var query = from d in context.Destinations
where d.Country == "Australia"
select d;
query.Load();
var count = context.Destinations.Local.Count;
Console.WriteLine("Aussie destinations in memory: {0}", count);
}
}
This time just the Destinations with Country set to Australia are loaded into memory.
When we run the application, we see that the count we get from Local is reduced to
reflect this.
Using Load on a LINQ query will bring the results of that query into
memory but it does not remove the results of previous queries. For ex-
ample if you called Load on a query for Australian destinations and then
Load on a query for American destinations, both Australian and Amer-
ican destinations would be in memory and would be returned from
Local.
Running LINQ Queries Against Local
So far we have just looked at getting the count from Local to make sure that it is re-
turning the correct data that we brought into memory. Because Local is just a collection
of in-memory objects, we can also run queries against it. One of the great things about
LINQ is that it’s not specific to Entity Framework. We can use the same LINQ syntax
to query a number of different data sources, including in-memory collections of objects.
Let’s add a LocalLinqQueries method that pulls data into memory using a single data-
base query and then runs some in-memory queries using Local (Example 2-21).
Example 2-21. Using LINQ to query Local
private static void LocalLinqQueries()
{
using (var context = new BreakAwayContext())
{
context.Destinations.Load();
var sortedDestinations = from d in context.Destinations.Local
orderby d.Name
select d;
Console.WriteLine("All Destinations:");
foreach (var destination in sortedDestinations)
{
Console.WriteLine(destination.Name);
Querying Local Data | 27
}
var aussieDestinations = from d in context.Destinations.Local
where d.Country == "Australia"
select d;
Console.WriteLine();
Console.WriteLine("Australian Destinations:");
foreach (var destination in aussieDestinations)
{
Console.WriteLine(destination.Name);
}
}
}
The code loads all Destinations into memory and then runs one query to sort them by
Name and another to pull out just the Australian Destinations. Remember that Find also
defaults to using in-memory data where possible. So we could also useFind and it would
use the data we loaded rather than sending more queries to the database.
While Load and Local are great if you want to reduce the number of queries that get
run against the database just remember that pulling all your data into memory may be
an expensive operation. If you are running multiple queries that only return a subset
of your data you’ll probably get better performance by letting these queries hit the
database and just pull back the data you actually need.
Differences Between LINQ Providers
There are a few subtle but important differences between querying directly against a
DbSet and against Local. These two data sources actually use two different LINQ pro-
viders. Querying against DbSet uses LINQ to Entities, which is specific to Entity Frame-
work and uses your model and mapping to turn your query into SQL that is executed
in the database. However, querying against Local uses LINQ to Objects, which per-
forms filtering, sorting, and similar operations in memory using the standard .NET
operators for testing equality, determining ordering, and the like.
The same query syntax can return different results depending on which one you are
using. For example, the database is typically not case-sensitive when comparing string
values, but .NET is. If you issued a query for Destination names that contain “great”,
the database would return “Great Barrier Reef” and “The great wall of China.” The
same query against Local would return “The great wall of China” but would not return
“Great Barrier Reef” because the capitalization of “great” is different.
Most LINQ providers support the same core features, but there are some differences
in features between each provider. For example, LINQ to Objects supports the Last
operator but LINQ to Entities does not. Therefore, you can use Last when running
queries against Local but not when running queries directly against a DbSet.
28 | Chapter 2: Querying with DbContext
Working with the ObservableCollection Returned by Local
If you’ve looked at the API closely you may have noticed that Local returns an Observ
ableCollection<TEntity>. This type of collection allows subscribers to be notified
whenever objects are added or removed from the collection. ObservableCollection is
useful in a number of data-binding scenarios, but it can also be useful if your application
needs to know when new data comes into memory.
Local will raise the CollectionChanged event whenever the contents of Local change.
This can be when data is brought back from that database via a query, when new objects
are added to the DbContext, or when objects previously brought into memory are
marked for deletion.
Let’s add a ListenToLocalChanges method that uses this functionality to log any changes
to Destinations.Local to the console (Example 2-22).
Example 2-22. Using CollectionChanged to print out changes to Local
private static void ListenToLocalChanges()
{
using (var context = new BreakAwayContext())
{
context.Destinations.Local
.CollectionChanged += (sender, args) =>
{
if (args.NewItems != null)
{
foreach (Destination item in args.NewItems)
{
Console.WriteLine("Added: " + item.Name);
}
}
if (args.OldItems != null)
{
foreach (Destination item in args.OldItems)
{
Console.WriteLine("Removed: " + item.Name);
}
}
};
context.Destinations.Load();
}
}
The code adds a new event handler to the Local collection of Destinations. This handler
looks at items entering or leaving the collection and prints out the name of the affected
Destination and indicates if it is being added or removed. Once the event handler is in
place, we use Load to pull all the data from the database into memory. If you run the
application, you can see the output appearing as items are returned from the database:
Querying Local Data | 29
Other documents randomly have
different content
The Project Gutenberg eBook of The great
illusion
This ebook is for the use of anyone anywhere in the United States
and most other parts of the world at no cost and with almost no
restrictions whatsoever. You may copy it, give it away or re-use it
under the terms of the Project Gutenberg License included with this
ebook or online at www.gutenberg.org. If you are not located in the
United States, you will have to check the laws of the country where
you are located before using this eBook.
Title: The great illusion
Author: Manly Banister
Illustrator: Kelly Freas
Release date: April 12, 2024 [eBook #73383]
Language: English
Original publication: New York, NY: Headline Publications, Inc, 1956
Credits: Greg Weeks, Mary Meehan and the Online Distributed
Proofreading Team at http://www.pgdp.net
*** START OF THE PROJECT GUTENBERG EBOOK THE GREAT
ILLUSION ***
THE GREAT ILLUSION
By MANLY BANNISTER
illustrated by KELLY FREAS
There was something phony about the whole set-up on
that planet. Their culture was counterfeit. But why
did they go to so much trouble to put on their act?
[Transcriber's Note: This etext was produced from
Super-Science Fiction February 1957.
Extensive research did not uncover any evidence that
the U.S. copyright on this publication was renewed.]
Cliff Rowley's lean jowls beaded with sweat in the stagnant warmth
of the tent. He tapped a bony finger on the camp table and glared at
the communicator.
"Clear out in a week! Why?"
Commander Waldo Spliid's tired voice trickled from the
communicator grid. Rowley would have appreciated video hook-up
now. He wondered how Spliid's features portrayed his thoughts.
"Here's final classification on Hume, Cliff. Category two X sub one."
"Closed world!" Rowley groaned. "We've only been here three
months!"
"Eleven men in the field, Cliff. You're the odd ball. Everybody else is
satisfied. Hume is only a step above savagery in culture. Top rating
is satisfied. I don't like the conflicting picture of it, myself, but...."
"Nor I," Rowley stabbed. The look in his hazel eyes hardened.
"You wouldn't," Spliid said calmly, "even without seeing the reports.
You're a percie, Cliff—our only psi-sensitive on Hume. But you've got
to do a lot more than you've done yet to impress top rating. They're
keener on the things you can't do than the things you can."
"A few more months, Commander...."
"A week, Cliff. Seven days. Get in and dig for all you're worth."
"Me and my little psychic shovel," Rowley commented bitterly.
A hum came out of the comm. Somewhere, far above the
atmosphere of Hume, the Survey ship, with Spliid on board, cruised
among the stars.
"Clean up any questions you can," Spliid went on. "Bring your notes
up to date. The pilot boat will pick you up ... let's see ... this is
Wednesday ... Wednesday for us, anyway. Next Wednesday, then.
Have everything ready to load. And keep on reporting."
Rowley started to retort, thought better of it. He switched off the
comm.
Well, that did it. They'd had it, as far as Hume was concerned. And
the puzzle still stared him in the face—him, Rowley, the boy who was
going to do great things, like with teleconscious apprehension, with
psychometry, with....
Psi-sensitives were new in the Galactic Ethnological Survey Corps—
Galethsurv in the cryptic, telegraphic coding of service vernacular.
Spliid had not been sarcastic when he had called Rowley a "percie",
the abbreviated, half-humorous, half-scornful, scuttle-butt
designation for the percipients.
Percipiency was still too new in the ethnological service to evaluate.
A percie had hunches and feelings he was supposed to follow.
Sometimes, it seemed, a percipient vaulted completely over painful
steps of reasoning and "cogged" a conclusion that was often correct.
The ability could be valuable, if properly used. That's where Rowley's
harness rubbed. His wasn't being used.
He knew something was wrong on Hume. But if Galethsurv wanted
to overlook his recommendation for further study, it should be no
concern of his.
But he couldn't run away from a problem that challenged him to
solve it.
Long grass swished against his calves as he strolled thoughtfully
down toward the village of thatched, stone houses, bathed in the
pink glow of a setting sun. Blue smoke curled lazily over stone
chimneys, and even from this distance, he could hear the sharp,
shrill voices of children raised in play. He took in the scene with a
single glance, the stream running beside the village, the small,
brown figures darting about the grassy lanes.
The village was nestled in a hollow of the rolling land. Beyond it and
stalking around it to enclose it in a clasp of balsam, lay the great
pine forest of Hume. Not really pine, but an other-world equivalent
of it, each tree spaced a precise, geometrical distance from its
neighbor, towering toward flecks of burnt-orange and mauve-colored
clouds in the aquamarine sky.
The forest of Hume was gigantic, mystifying. It challenged the mind.
It covered the whole land surface of Hume with its geometrical
spacing of trees. And the people who populated Hume called
themselves Keepers of the Trees.
Rowley tried to grasp the fact that what he saw here was almost
endlessly repeated over the broad face of Hume. Why did he think
that the real culture of Hume was otherwise than what he saw? A
thousand thousand villages, purpling in the swift-rushing sunset ... a
myriad of slender semi-savages, who spent their lives tending the
trees. If he, Rowley, could perceive more than other men, then what
did he perceive here? He wished he knew.
What was the real culture? What lay behind this facade? Why did he
think the impressions of his ordinary senses reported only the
outward effect of a mere stage play? It was a mighty big play,
performed for a very small audience—the eleven investigators for
Galethsurv. How could he get to the bottom of the puzzle in the few
days remaining, with no more guide than an inexplicable "feeling" of
falseness? Time was so short!
The illusion of reality in the village was strong enough to overwhelm
him. Teramis was scratching in his garden while the light faded from
the sky. He waved and called out to Rowley as he went by. Teramis
had spent the day, with the rest of the villagers, among the trees,
removing moss and insects, clipping dead branches ... why?
Shy, big-eyed little kids, showing brown where they weren't clothed,
ran in the grassy streets. Unusually—unnecessarily—clean for the
offspring of a semi-savage people, he thought.
Tsu was drawing water from the creek as he came up. She paused,
holding the water jar against youthful breasts, restrained under the
taut fabric of her yellow sarong. Like others of her race, she was
surpassingly slender, breathtakingly beautiful in the liquid melody of
her movements. Her face was long, tanned, glowing with the
ripeness of youth. Her eyes, long, tip-tilted, were lidded with
mystery, and her black hair was substanceless shadow caressing her
shoulders.
It almost came to him as he looked at her, greeted her. Did Tsu look
the part of a shy, savage maiden of the wild? He had to admit that
she did ... she looked like an over-enthusiastic video casting
director's idea of category two X sub one maidenhood.
The implications slipped from his mind as she clasped his hand. The
warm flesh of her palm felt firm against his.
An electric tingle wriggled up his arm. Not even the rigor of his
emotional conditioning could have prevented that much. It was not
good for field men to be bothered by emotions. It made their work
difficult; they found wives on sub-standard worlds and wanted to
bring them out to civilization; or, they reverted to the wilds
themselves with their mates. The Corps conditioned its men against
anything like that, so that emotional vagaries could not disturb the
single-mindedness trained into them—to discover and interpret in
the field.
"Good evening, sintaha Rowley," Tsu said.
He followed her into the house she shared with Smarin and Torl, her
parents. They greeted Rowley warmly, slim, smiling, happy as usual.
It was a stage play, performed for his benefit. He moved around
among the actors, but he was not an actor himself. He was the
audience.
Rowley had been in this house often, always with a haunting sense
of wrongness. He knew it as well as he knew his own tent. Living
room, kitchen, two bedrooms and quarters for bathing. Clean
people, the natives of Hume.
Rowley sat on the stone stoop and contemplated the gathering
shadows. Tsu came out and sat close beside him. He asked her
again about the trees, why the people tended them.
"It is proper to tend the trees, sintaha Rowley. We have done so
always."
Was she evading? Or did he fully understand her language, simple
as it was? He had learned it quickly, and had wondered at the time
that it was so similar in grammar and syntax to his own. An odd
coincidence—or deliberate casting, to impress the play more easily
on the audience?
"Tomorrow," he said, "I should like to learn more about the trees."
"If it will please you," she said.
Another sun was setting. Another day had gone to join the fruitless
ones preceding it. The expedition among the trees had told him
nothing. Everything was the same as Tsu had explained several
times before. His alerted senses found no discrepancy. He was
disappointed, and he said as much in his evening report to
Commander Spliid.
"It adds up," Spliid said encouragingly.
Rowley felt a glow.
"You get it?"
"No, frankly. But top rating must have the right slant. Where does
percipiency leave off and old fashioned imagination begin? You're
functioning like a percie, even when there's nothing to perceive."
"I thought you weren't satisfied...."
"I'm not a percie, Cliff. Any dissatisfaction I may feel is aroused by
the conflicting reports of the field men. Anyway, we can probably
clear that up in the correlating department."
Rowley's heart sank. "You are satisfied!"
The speaker hummed. Spliid said, flatly, "I've got to be. Everybody
else is ... except you."
Rowley grunted. "Six days! I'll try to uncover something."
Spliid's voice sounded worried. "I hate this, Cliff. Your talents can be
valuable to the Corps. We deal in cubic parsecs of space and aeons
of time. It takes more than ordinary reasoning power to cope with
it."
"I believe you mean it," Rowley said.
"I do. So what's Hume? One world in millions."
Rowley's switched him off. He bit his lip. It was Galethsurv's purpose
to make single, cohesive sense out of the patch-work, and
tatterdemalion shreds of human culture that had been systematically
turned up in the galaxy. Where did the culture of Hume fit into that
overall pattern?
Galethsurv believed that the distribution of mankind among the stars
had not been accident. Where, then, had Man originated? It was
important to know. Remembrance of yesterday points the way
toward a more highly educated guess about tomorrow. Someday,
Man would find out if—or why—he had been deliberately seeded
among the stars. And then...?
"Sintaha Rowley, are you not also Keepers of the Trees on your own
world?"
Tsu was so earnest with the question, Rowley was surprised. He
made a wry grimace, half humorous.
"Of course, we grow trees for fruit, for shade and beauty, to cut
down and make lumber for houses...."
She drew away from him, rigid, trembling.
"You cut down trees!"
He hadn't meant to make that slip. He knew her feeling for trees.
Her look accused him.
"I don't understand your attitude," he said lamely.
"Nor do I understand yours." She brooded silently. "It is different, I
suppose, on other worlds. The trees are different."
They sat in the lush grass, on the hillside below his tent. The toy
village lay at their feet, a cardboard set in miniature.
"Your people puzzle us, Tsu. You are too different from us...."
"We have tried to make it easy for you," she murmured.
Easy? Too easy, he thought. It was all too plain, too easy to
understand. That's why he couldn't understand a bit of it.
"We hope," he went on, "that by studying your world and others like
it, we may some day better understand the whole universe...."
"Or reach a better understanding of your own thoughts?"
She smiled. Her long eyes lidded heavily with amusement.
"Wherever we go," he continued doggedly, "we find people like
ourselves. Human beings. They are born; they grow up; they die.
Human culture is built around the processes of living and dying. Our
beliefs and actions stem from those facts—that we live and that we
die. We are emotionally affected by them. Sometimes, we know
great happiness. Then we remember that we die, and we suffer
sorrow. I have seen no sadness in your village. Everybody is happy.
It ... it isn't natural. I wonder how you would act if one of you were
to die...."
She stirred restlessly, movement restricted by her clinging sarong.
"One of us will die for you," she said simply, "if you wish to study it."
Sudden shock hammered at his brain. What a thing to say! What did
she mean? Was she really as simple as her language seemed to
indicate? He felt embarrassed.
"Tsu, you know I didn't mean...."
His eye caught a flicker of movement among the brown trunks of the
trees. A slim figure left their shadow, picked its way uphill through
the grasses, toward them. Rowley recognized Smarin, Tsu's father.
Smarin's slim ascetic face was expressionless, his long eyes hooded.
"Torl fell from the tree," he said. "Torl is dead. Come, Tsu."
Rowley felt hair prickle at the back of his neck. It seemed that
Smarin had come out, strictly on cue. Then he realized that Smarin
had meant it. The shock of a moment before intensified, expanded,
pressurized itself into every cell of his brain.
"Oh, no!" he said.
Tsu got lithely up. She looked down at him, lips drawn, eyes lidded
with slumbering sorrow.
"It was your wish, sintaha Rowley. Come with us. Study and
learn...."
"It could have been an accident," Rowley reported over the comm,
"but I have a feeling it was staged."
"You saw the dead woman?"
"She was dead, all right. They let me see that she was dead, then
they buried her—at the foot of the tree. No ceremony. Shallow grave
—not over a foot and a half deep."
"Then what?"
"Then they all went back to tending the trees. Tsu seemed happy as
hell about the whole thing. She hoped I had learned what I wanted,
she said."
"I'm interested," Spliid broke in. "I'm coming down tonight, Cliff."
"Where are you now?"
"About a thousand miles east of you. I looked in on Stephans this
afternoon. I'll get down there after dark."
Sunsel glowed an arabesque of colors on the village at Rowley's feet.
The comm was silent. He switched it off.
Commander Waldo Spliid was a big, blond man. He bulked hugely at
Rowley's side, among the intense shadows of the trees. Hume had
no moon. Only the stars spattered a frail shine over the upper levels
of the forest.
Rowley said, softly, "Here's the grave."
Spliid flashed a light, briefly.
"What did they dig it with?"
"Spade—shovel."
"Steel blade?"
"Iron, anyway. I reported on that I don't know where they get
metals."
Spliid flashed his light again, grunted.
"No marker."
Rowley nodded. "That's right. I thought about it at the time and
wondered. I thought of mentioning it to Tsu. Know why I didn't?"
Spliid grunted again.
"I thought, if I did, somebody would come out of the trees, bringing
a marker. Probably two sticks tied in a cross. Get what I mean?"
"Gimme the shovel," said Spliid.
Rowley handed him the collapsible entrenching tool he had been
carrying. The Commander bent his back, scooped at the dirt. He
worked swiftly, carefully, almost silently.
"About eighteen inches deep, you said?"
"About."
Spliid fell to again. The metal blade chinked dully on moist clods.
After a time, Spliid flashed his light again. His free hand entered the
cone of yellow shine, prodded the moist dirt. He was on his knees,
reaching far down into the hole he had dug.
"I've gone by loose dirt," he puffed. "There's no body here, Cliff."
"She was dead and I saw them bury her," Rowley insisted
stubbornly. "Maybe hypnotism. I felt they were putting on a show for
me. I keep asking myself why, and then I turn to the facts."
"What facts?"
"Why...." Rowley hesitated. "Hume has been classified a closed
world. I think that's what they want. If this world had been
uninhabited when Exploration turned it up, Colonisation would be
surveying it now for settlement. If the population had a civilization
above Class G, we'd be arranging to bring them up to the
technological level of the rest of the galaxy. But we shut a two X sub
one world away from contact with the galaxy to avoid disturbing the
natural progress of the natives. How many thousands of years
before Hume will be ready? Somehow, I feel they know more about
us than we think they do ... and they're only too happy to be left to
themselves."
"Rubbish! Why?"
"Why do they want it, or why do I think so? I don't know the answer
either way. If you've ever seen a stage play, you'll understand what I
mean. Everything about a stage play is phoney. You watch the play,
knowing it isn't real. The scenery and backdrop are just painted
imitations. All right—but the actions of the characters on the stage
serve something like a catalyst. Your faculties of critical observation
are suspended, and the play becomes real. For the time of the play,
you are caught up in the illusion of reality that grips you. That's the
way it is here on Hume.
"You look around you in the broad light of day. You see a pastoral
idyll. Everybody's happy. Everybody gets along with everybody else.
All the people are beautiful, agreeable and kind. They have a simple
culture, too far down the scale to admit to intercourse with the rest
of the galaxy.
"Look twice, though, and you see something else...."
"All right," said Spliid. "Let's get back to camp."
The sloping canvas top of Rowley's tent bulked dimly in the starlight.
Spliid laid a heavy hand on Rowley's arm.
"I've been thinking, Cliff. There was never a body in that grave."
Rowley started. "Never was?"
"Don't ask me. It's your idea, with talk of stage plays and phoney
accidents. You made me feel it. I come down to find out. You've
been the victim of something ... I don't know what. Are you
comforted?"
"No. If only we had more time!"
"We've got a few days," Spliid reassured him. "You've got a good
idea in that stage play simile. But the actors aren't very good, and
the directing is abominable. It takes a lot of rehearsal to make a
good play, Cliff."
For a long time after the pilot boat drifted down from the upper air
and whispered away toward the stars with Commander Spliid,
Rowley stood brooding, looking down into the pool of shadows
hiding the village.
Stage play. Actors. What happens to the scenery when the audience
goes home? Rowley shrugged and went to bed.
In the morning, Rowley stirred together an unpalatable breakfast,
then went down into the village. The natives were already stirring.
Children ran in the grassy streets. The solid stone of the houses
gleamed white and gray, streaked and spotted with brown,
crumbling at the corners. The thatched roofs were ochre, glistening
blue-grey with dew.
Painted scenery? The slender, racing children—hired extras? And Tsu
—the leading lady?
He felt miserable about disturbing Tsu and Smarin today. It was
intrusion on their period of mourning. Did they mourn on Hume?
There was nothing of mournful bereavement about the little stone
house, gay in the sunshine, with its clustering border of purple, rose
and yellow flowers. The inside was dark-brown dim, but he caught a
glimpse of movement. He stepped to the door, leaned with his hand
on the jamb, waiting to be noticed.
"Sintaha Rowley! Good morning. Here is Tsu."
Rowley dug his nails into the door post. Tsu came out skipping, but
he was unaware of her. Torl ... Torl who was dead yesterday ...
smiled at him and retreated into the interior.
Tsu took his hand, brushing against him with her usual easy
familiarity. He realized that his fingers trembled in her grip.
He said, hoarsely, "That was Torl ... in there!"
Tsu laughed up into his face, long eyes bright.
"Why not? It is Torl's house, too!"
"But ... but ... yesterday...." He couldn't bring himself to say that
yesterday Torl had died and he had seen her buried.
Tsu seemed to divine the thought in his mind.
"Yesterday was yesterday, sintaha Rowley. Yesterday, Torl died, and
you saw how it was. We hope you could make a good report of it."
He was silent as they walked. He stole occasional glances at her,
wondering. Somehow, the death and resurrection of Torl provided a
key. His brain was swamped with conjecture.
They left the village and climbed the hill. He had meant to sit with
Tsu and Smarin, to share their grief a while this morning, if they
would let him. Why he walked now, he could not say, save that his
brain was in a whirl. And Tsu accompanied him gaily, chattering
nonsense about the death of her mother.
He stopped, looked at the village below. While they were here, he
would ask Tsu for information about who lived where. He had
already sketched the village from his tent. He would write in the
information as an addition to his notes.
A thought struck him. Why label the props on the stage set? Labels
meant nothing ... unless you could see the set from the wings. It
would help, if he could do that.
"Let's sit here, Tsu," he said.
She sat, obediently, among the tall grasses, folding slim, long legs
under her like a child. He sat at her side, noting with relief that a
slight hump in the slope hid the village from sight. He took her hand
in his.
"I have thought of something," he said carefully. "Tell me about the
children. Let's take Yanek ... is that his name? He lives in the house
next to you. How old is he?"
She regarded him from the corners of her long eyes.
"Old? Yanek is as old as a child. He is as old as he is."
"How old is Yanek in years?"
She hesitated, biting her lip in puzzlement. "There is always Yanek,
sintaha Rowley. Why should there be anything about him of years?"
She didn't know what he was talking about. Rowley felt excitement
creep along the channels of his veins.
"Can you remember when Yanek was born?"
The look in her eyes made his heart pound harder. She was alarmed!
He pressed on, relentlessly. "Yesterday, Torl died. Today, she lives.
You do not understand a simple thing like age. You do not remember
when Yanek was born, but he is not over seven or eight. Tsu ... tell
me ... are you and your people immortal?"
There was an anguish in his tone that made her drop her eyes.
"No," she said, without moving her lips.
That was the truth. His inner sense told him it was. And the truth
was disappointing. What had he expected? The key to immortality?
The Fountain of Youth? Men had sought it in ages past and never
found it.
His thoughts darted. "If you cannot remember Yanek being born,
perhaps he was not born. Yet, you have families. There must be
love...."
"Love, yes! We love each other, we love our world, our trees...."
"And if a young man loved you, Tsu, how would he say it?"
His heart was pounding fiercely now. A fierce zeal possessed him
that was not born of her nearness, the intimacy of their seclusion.
His conditioning against emotional storms had been too thorough for
him to break it now. It was something else that possessed him—the
excitement of the hunter viewing the first, sparse tracks of the game
he seeks. He had asked. It all depended now on her answer, for the
mystery was coming clear to him.
Her long eyes were heavy-lidded, candid, without guile.
"How would he among your people, sintaha Rowley?"
He thought, wildly, she doesn't know! He thought, she is
inexperienced. He thought again, she would never know, unless...."
He slipped an arm around her bare shoulders and drew her to him.
"Like this," he said, looking down into her tip-tilted eyes.
Then he kissed her. Her sarong slipped....
"I am unhappy with you, Cliff," Commander Spliid said with chilly
formality. Rowley leaned back in his chair in Spliid's office aboard the
Survey ship. Spliid laid his pipe in the tray on his desk. He said,
"What happened to your daily reports?"
Rowley stuffed his own pipe, lit it.
"I thought you knew. I didn't make any."
Spliid's look of exasperation wavered and dimmed through the swirls
of blue smoke. It was all over now, and Rowley felt no sense of
hurry. Hume was a pinpoint of light in the star-carpeted vestibules of
space behind them. In another hour, they would shift into overdrive.
Hume would vanish from their lives forever.
"I assume," he said, "that Hume is now officially closed."
Spliid nodded. He fixed questioning gray eyes on Rowley.
"Good," said Rowley. "That's the way it will always be."
"Always?" Spliid fumbled with his pipe. "For our life-times, maybe...."
"Always," Rowley repeated. He drew on his pipe, enjoying the luxury
of keeping the Commander's curiosity at bay. "Human beings have
no place on Hume. I found that out the day after you dropped in on
me. That's why I made no reports. I just sat around, waiting for the
pilot boat."
Spliid held a lighter to the dark-stained bowl of his pipe.
"So you're satisfied now, too?"
Rowley nodded noncommittally. "At first," he said distantly, "I
imagined crazy things—like a super-advanced race living
underground, giving us the bum's rush with a play-show they had
rigged up."
"And you found out you were wrong," suggested Spliid.
"I found out I was partly right."
"I won't buy supermen living in caves, Cliff."
"Neither would I. The next crazy thing I thought was that the natives
were immortals and they didn't want us to share in it. Silly, huh?"
"Pretty silly," Spliid agreed drily.
"I knew they wanted to get rid of us," Rowley went on earnestly. "I
could feel it. But why? Most inferior races we run against want
contact with the galaxy...."
"They want refrigerators and washing machines, tractors, railroad
trains and automobiles," Spliid interrupted. "If we gave them, their
culture would go to pot in a generation. There's a reason for our
methods."
"A lot of little things about Hume didn't jibe," Rowley continued.
"Bathrooms, for instance."
"No bathrooms on Hume?" Spliid grinned.
"Bath rooms, yes. Just bathing went on in there. And outside, where
the little house in back ought to be ... nothing." Rowley tamped the
ashes in his pipe, withdrew a blackened finger. "We take that sort of
thing for granted, you know. We assume proper facilities are around
someplace and don't give them a second thought. They weren't
present in the stage setting because they weren't needed."
"Come, now...!"
"Fact. Another fact: grass growing in the streets. The way those kids
played on it, it would have been worn away in a week. Slim
evidence, but it's part of the picture."
"What I'm interested in," said Spliid, "is the death. Did you learn
what they did with the body?"
"You were right," Rowley said. "There wasn't any. I saw Torl the next
day, alive and kicking. That's what put me off on the immortality
tangent."
Spliid grunted. "Another act in the play?"
"Yes, and badly directed. The director didn't understand death as we
do."
Spliid shook himself. "Now, wait...!"
"Honest and truly. How do we think of death—most of us? We
believe in somehow living on after death takes place—immortality of
the soul. Can you visualize how a stage director who didn't
understand that concept would cast it?"
"What do you think I am, a percie? Get on with it."
"Consider this, then. I gambled with my emotional adjustment
conditioning. There was one angle I hadn't exploited, because of
that conditioning. Sex."
"If you are trying to tell me you unloaded the conditioning we give
you," Spliid interrupted, "I won't believe it!"
"No—I wouldn't. But, in the interest of ethnological investigation, I
could grab a kiss. So I did."
"I see," drily.
"Not yet, you don't. I got no reaction. Like embracing a tree.
Anyway, I kissed her. Somehow...." He hesitated. "Her garment...."
"No wonder you made no report," growled Spliid. "Believe me, Cliff,
I'm going to have that conditioning process looked into!"
Rowley laughed, briefly. "No need for that. It's sound. You'll be
interested in what that slipping garment revealed."
"Another time, another place...."
"I saw a perfect, living statue!"
Spliid's eyes alerted. "A what?"
Spliid relaxed. "I think I know what you mean. Go on."
Rowley drew heavily on his pipe. A brooding look shadowed his lean
face.
"I learned about Yanek then. I learned about Tsu and Smarin and
Torl and all the rest of them. If we weren't such damned prudes,
Commander, and I had flipped a sarong sooner, we'd have found
everything out long ago. You've heard about the sinner who was told
he could remain in Heaven only on condition he could pick Adam out
of the crowd? He chose the only man he could find ... without a
navel."
"Maybe they lay eggs," Spliid suggested. "Oviparous."
Rowley gave him a look of humorous scorn. "Do statues lay eggs?"
Spliid's expression cleared. "By God! Now I really understand you!"
"The natives of Hume couldn't reproduce in any manner. Naturally, I
wanted to know why. And the answer came to me—protective
coloration ... camouflage!"
"Apparent. Camouflage for what?"
"You've heard the expression, if you can't lick 'em, join 'em...?"
"Sure, but...."
"But suppose you can't join 'em, either?" Rowley laughed, excitedly.
"You make like something they want to protect!... Know anything
about dryads, Commander?"
Spliid snorted. "Supernatural creatures that live in trees? Dryads
don't exist!"
"Neither do the people of Hume."
Spliid looked at him in such a way Rowley felt his sanity was being
weighed.
"Suppose you were a native of Hume, and some alien beings came
along. You could read their minds. You'd know right off they
wouldn't recognize you as a life-form like themselves. They might
move right in and destroy you without knowing it, and you would be
unable to defend yourself. That was actually the situation on Hume,
and we were the aliens. So the natives pretended they were a type
of life-form we want to protect."
"How was it done?" Spliid wanted to know.
"Mental projection. After the directors of the play read our minds,
they tried to reproduce what they found there. They slipped on the
points I mentioned, because those things meant little or nothing to
them. But they were enough to rob the play of its semblance of
reality.
"Tsu, Smarin, Torl ... even the village itself ... were all imaginary—
not something we thought we saw, but solidified mental projections
of the thoughts the natives had gleaned from our minds."
"I'm just beginning to see the real value of your talents, Cliff."
"Thanks," Rowley acknowledged briefly. "If we have the right to
exclude inferior cultures from contact with us, a superior culture
must certainly have an equal right to exclude us from contact with
theirs."
Spliid wagged his head, half smiling. His pipe had gone out and he
puffed at it without effect.
"I've been waiting for you to tell me who these 'directors' are," he
said.
Rowley grinned. "You won't believe this. The directors needed
something to keep their play actors busy ... some logical occupation
of their time. What could they find more logical—to them—than
taking care of trees? Because the directors themselves are the trees
—the living, intelligent forest of Hume. Fantastic, isn't it?"
Spliid sighed as if deeply gratified.
"If it weren't for one thing even more so, I'd say it was the most
fantastic thing I ever heard of."
"What's more fantastic than intelligent trees?"
"Human beings," said Spliid.
THE END
*** END OF THE PROJECT GUTENBERG EBOOK THE GREAT
ILLUSION ***
Updated editions will replace the previous one—the old editions will
be renamed.
Creating the works from print editions not protected by U.S.
copyright law means that no one owns a United States copyright in
these works, so the Foundation (and you!) can copy and distribute it
in the United States without permission and without paying
copyright royalties. Special rules, set forth in the General Terms of
Use part of this license, apply to copying and distributing Project
Gutenberg™ electronic works to protect the PROJECT GUTENBERG™
concept and trademark. Project Gutenberg is a registered trademark,
and may not be used if you charge for an eBook, except by following
the terms of the trademark license, including paying royalties for use
of the Project Gutenberg trademark. If you do not charge anything
for copies of this eBook, complying with the trademark license is
very easy. You may use this eBook for nearly any purpose such as
creation of derivative works, reports, performances and research.
Project Gutenberg eBooks may be modified and printed and given
away—you may do practically ANYTHING in the United States with
eBooks not protected by U.S. copyright law. Redistribution is subject
to the trademark license, especially commercial redistribution.
START: FULL LICENSE
THE FULL PROJECT GUTENBERG LICENSE
PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
To protect the Project Gutenberg™ mission of promoting the free
distribution of electronic works, by using or distributing this work (or
any other work associated in any way with the phrase “Project
Gutenberg”), you agree to comply with all the terms of the Full
Project Gutenberg™ License available with this file or online at
www.gutenberg.org/license.
Section 1. General Terms of Use and
Redistributing Project Gutenberg™
electronic works
1.A. By reading or using any part of this Project Gutenberg™
electronic work, you indicate that you have read, understand, agree
to and accept all the terms of this license and intellectual property
(trademark/copyright) agreement. If you do not agree to abide by all
the terms of this agreement, you must cease using and return or
destroy all copies of Project Gutenberg™ electronic works in your
possession. If you paid a fee for obtaining a copy of or access to a
Project Gutenberg™ electronic work and you do not agree to be
bound by the terms of this agreement, you may obtain a refund
from the person or entity to whom you paid the fee as set forth in
paragraph 1.E.8.
1.B. “Project Gutenberg” is a registered trademark. It may only be
used on or associated in any way with an electronic work by people
who agree to be bound by the terms of this agreement. There are a
few things that you can do with most Project Gutenberg™ electronic
works even without complying with the full terms of this agreement.
See paragraph 1.C below. There are a lot of things you can do with
Project Gutenberg™ electronic works if you follow the terms of this
agreement and help preserve free future access to Project
Gutenberg™ electronic works. See paragraph 1.E below.
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!
ebookultra.com

[FREE PDF sample] Programming Entity Framework DbContext 1st Edition Julia Lerman ebooks

  • 1.
    Download the fullversion of the ebook now at ebookultra.com Programming Entity Framework DbContext 1st Edition Julia Lerman https://ebookultra.com/download/programming- entity-framework-dbcontext-1st-edition-julia- lerman/ Explore and download more ebook at https://ebookultra.com
  • 2.
    Recommended digital products(PDF, EPUB, MOBI) that you can download immediately if you are interested. Professional ADO NET 3 5 with LINQ and the Entity Framework 1st Edition Roger Jennings https://ebookultra.com/download/professional-ado-net-3-5-with-linq- and-the-entity-framework-1st-edition-roger-jennings/ ebookultra.com Julia High Performance Programming Learning Path 1st Edition Ivo Balbaert https://ebookultra.com/download/julia-high-performance-programming- learning-path-1st-edition-ivo-balbaert/ ebookultra.com Database Design Using Entity Relationship Diagrams 1st Edition Sikha Bagui https://ebookultra.com/download/database-design-using-entity- relationship-diagrams-1st-edition-sikha-bagui/ ebookultra.com Kierkegaard 1st Edition Julia Watkin https://ebookultra.com/download/kierkegaard-1st-edition-julia-watkin/ ebookultra.com
  • 3.
    Needlework 1st EditionJulia Watts https://ebookultra.com/download/needlework-1st-edition-julia-watts/ ebookultra.com Gene Cloning 1st Edition Julia Lodge https://ebookultra.com/download/gene-cloning-1st-edition-julia-lodge/ ebookultra.com Julia High performance 1st Edition Avik Sengupta https://ebookultra.com/download/julia-high-performance-1st-edition- avik-sengupta/ ebookultra.com Powers A History 1st Edition Julia Jorati https://ebookultra.com/download/powers-a-history-1st-edition-julia- jorati/ ebookultra.com Learning to Think Strategically 1st Edition Julia Sloan https://ebookultra.com/download/learning-to-think-strategically-1st- edition-julia-sloan/ ebookultra.com
  • 5.
    Programming Entity FrameworkDbContext 1st Edition Julia Lerman Digital Instant Download Author(s): Julia Lerman, Rowan Miller ISBN(s): 9781449312961, 1449312969 Edition: 1 File Details: PDF, 7.20 MB Year: 2012 Language: english
  • 8.
    Programming Entity Framework: DbContext JuliaLerman and Rowan Miller Beijing • Cambridge • Farnham • Köln • Sebastopol • Tokyo
  • 9.
    Programming Entity Framework:DbContext by Julia Lerman and Rowan Miller Copyright © 2012 Julia Lerman and Rowan Miller. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://my.safaribooksonline.com). For more information, contact our corporate/institutional sales department: (800) 998-9938 or corporate@oreilly.com. Editors: Meghan Blanchette and Rachel Roumeliotis Production Editor: Teresa Elsey Cover Designer: Karen Montgomery Interior Designer: David Futato Illustrators: Robert Romano and Rebecca Demarest Revision History for the First Edition: 2012-02-23 First release See http://oreilly.com/catalog/errata.csp?isbn=9781449312961 for release details. Nutshell Handbook, the Nutshell Handbook logo, and the O’Reilly logo are registered trademarks of O’Reilly Media, Inc. Programming Entity Framework: DbContext, the image of a great African heron, and related trade dress are trademarks of O’Reilly Media, Inc. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in this book, and O’Reilly Media, Inc., was aware of a trademark claim, the designations have been printed in caps or initial caps. While every precaution has been taken in the preparation of this book, the publisher and authors assume no responsibility for errors or omissions, or for damages resulting from the use of the information con- tained herein. ISBN: 978-1-449-31296-1 [LSI] 1330008698
  • 10.
    Table of Contents Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix 1. Introducing the DbContext API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Getting the DbContext API into Your Project 2 Looking at Some Highlights of the DbContext API 3 Reducing and Simplifying Ways to Work with a Set 5 Retrieving an Entity Using ID with DbSet.Find 5 Avoiding Trolling Around the Guts of Entity Framework 6 Working with the BreakAway Model 6 Getting the Sample Solution 6 Getting DbContext from an EDMX Model 8 Ensuring DbContext Instances Get Disposed 11 2. Querying with DbContext . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Writing Queries with LINQ to Entities 13 Querying All the Data from a Set 16 Using LINQ for Sorting, Filtering, and More 18 Finding a Single Object 21 Querying Local Data 24 Using the Load Method to Bring Data into Memory 26 Running LINQ Queries Against Local 27 Working with the ObservableCollection Returned by Local 29 Loading Related Data 30 Lazy Loading 31 Eager Loading 33 Explicit Loading 36 Checking If a Navigation Property Has Been Loaded 38 Querying Contents of a Collection Navigation Property 39 Explicit Loading a Subset of the Contents of a Navigation Property 41 iii
  • 11.
    3. Adding, Changing,and Deleting Entities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Working with Single Entities 44 Adding New Entities 44 Changing Existing Entities 45 Deleting Existing Entities 46 Multiple Changes at Once 51 The “Find or Add” Pattern 52 Working with Relationships 53 Adding a Relationship Between Objects 54 Changing a Relationship Between Objects 56 Removing a Relationship Between Objects 57 Working with Change Tracking 59 Using Snapshot Change Tracking 60 Understanding When Automatic Change Detection Occurs 60 Controlling When DetectChanges Is Called 60 Using DetectChanges to Trigger Relationship Fix-up 63 Enabling and Working with Change Tracking Proxies 64 Ensuring the New Instances Get Proxies 67 Creating Proxy Instances for Derived Types 68 Fetching Entities Without Change Tracking 69 4. Working with Disconnected Entities Including N-Tier Applications . . . . . . . . . . . . . 71 A Simple Operation on a Disconnected Graph 72 Exploring the Challenges of N-Tier 74 Using Existing N-Tier Frameworks That Support Graph Modification 76 Using Explicit Operations on the Server Side 77 Replaying Changes on the Server 77 Understanding How DbContext Responds to Setting the State of a Single Entity 78 Marking a New Entity as Added 79 Marking an Existing Entity as Unchanged 80 Marking an Existing Entity as Modified 81 Registering an Existing Entity for Deletion 83 Working with Relationships with and Without Foreign Keys 85 Setting the State for Multiple Entities in an Entity Graph 88 Getting the Graph into the Context 88 Setting the State of Entities in a Graph 90 Building a Generic Approach to Track State Locally 92 Creating a Generic Method That Can Apply State Through Any Graph 96 Concurrency Implications 98 Tracking Individually Modified Properties 99 Recording Modified Property Names 99 Recording Original Values 102 iv | Table of Contents
  • 12.
    Querying and ApplyingChanges 106 5. Change Tracker API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 Change Tracking Information and Operations for a Single Entity 111 Working with the State Property 112 Working with Current, Original, and Database Values 113 Working with DbPropertyValues for Complex Types 119 Copying the Values from DbPropertyValues into an Entity 122 Changing Values in a DbPropertyValues 123 Working with Individual Properties 128 Working with Scalar Properties 128 Working with Complex Properties 131 Working with Navigation Properties 133 Refreshing an Entity from the Database 137 Change Tracking Information and Operations for Multiple Entities 139 Using the Change Tracker API in Application Scenarios 141 Resolving Concurrency Conflicts 141 Logging During Save Changes 147 6. Validating with the Validation API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 Defining and Triggering Validation: An Overview 154 Validating a Single Object on Demand with GetValidationResult 155 Specifying Property Rules with ValidationAttribute Data Annotations 157 Validating Facets Configured with the Fluent API 158 Validating Unmapped or “Transient” Properties 158 Validating Complex Types 159 Using Data Annotations with an EDMX Model 159 Inspecting Validation Result Details 160 Inspecting Individual Validation Errors 161 Exploring More ValidationAttributes 163 Using CustomValidationAttributes 164 Validating Individual Properties on Demand 166 Specifying Type-Level Validation Rules 166 Using IValidatableObject for Type Validation 167 Validating Multiple Rules in IValidatableObject 169 Using CustomValidationAttributes for Type Validation 171 Understanding How EF Combines Validations 173 Validating Multiple Objects 175 Validating When Saving Changes 178 Reviewing ObjectContext. SaveChanges Workflow 179 Understanding DbContext.SaveChanges Workflow 179 Disabling Validate Before Save 182 Table of Contents | v
  • 13.
    7. Customizing Validations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 Overriding ValidateEntity in the DbContext 183 Considering Different Ways to Leverage ValidateEntity 187 Updating Data During SaveChanges 192 Overriding SaveChanges When Validation Occurs 193 Comparing ValidateEntity to SaveChanges for Custom Logic 197 Using the IDictionary Parameter of ValidateEntity 198 Controlling Which Entities Are Validated in ValidateEntity 200 8. Using DbContext in Advanced Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 Moving Between ObjectContext and DbContext 203 Accessing ObjectContext Features from a DbContext 204 Adding DbContext into Existing .NET 4 Applications 205 Leveraging SQL Server Operators Exposed in SqlFunctions 208 Querying Derived Types with DbSet 209 Understanding the Interface Property Limitation 210 Considering Automated Testing with DbContext 210 Testing with DbSet 211 Exploring a Scenario That Unnecessarily Queries the Database 212 Reducing Database Hits in Testing with IDbSet 214 Creating an IDbSet Implementation 214 Abstracting BreakAwayContext for Tests 217 Reviewing the Implementation 221 Supplying Data to a FakeDbSet 221 Accessing the Database Directly from DbContext 222 Executing Queries with Database.SqlQuery and DbSet.SqlQuery 223 Tracking Results of SqlQuery 226 Executing Commands from the Database Class 226 Providing Multiple Targeted Contexts in Your Application 227 Reusing Classes, Configurations, and Validation Across Multiple Contexts 227 Ensuring That All DbContexts Use a Single Database 231 Validating Relationship Constraints and Other Validations with Mul- tiple Contexts 232 Getting Code First to Create Full BreakAwayContext Database 232 9. What’s Coming Next for Entity Framework . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 Understanding Entity Framework’s Version Numbers 235 Entity Framework 5.0 236 Enums 236 Spatial Data 236 Performance Improvements 236 Multiple Result Sets from Stored Procedures 237 vi | Table of Contents
  • 14.
    Table Value Functions237 Table of Contents | vii
  • 16.
    Preface Microsoft’s principal dataaccess technology, ADO.NET Entity Framework, has had two major releases as part of the .NET Framework. .NET 3.5 brought us the first version of Entity Framework, which is covered in the first edition of Programming Entity Framework (O’Reilly). In 2010, Microsoft .NET 4 was released, containing the next versionofEntityFramework,referredtoasEntityFramework4.Thecompletelyrevised second edition of Programming Entity Framework (O’Reilly) was dedicated to teaching readers how to use this version of Entity Framework in Visual Studio 2010. When .NET 4 was released, the Entity Framework team was already hard at work on a new addition, called Code First, to provide an alternative way of building the Entity Data Model that is core to Entity Framework. Rather than using a visual designer, Code First allows you to create the model from your existing classes. At the same time, the team devoted resources to making Entity Framework easier to use. They focused on the most commonly used features and tasks in Entity Framework and built a new API called the DbContext API. This book is dedicated to teaching readers how to use the features of the DbContext API. In addition to the DbContext class, you’ll find the DbSet class for performing set operations, improved APIs for change tracking and handling concurrency conflicts, and a Validation API that integrates with validation features already present in .NET. In this book, you will learn how to query and update data using the new API, whether you are working with individual objects or graphs of objects and their related data. You’ll learn how to take advantage of the change tracking features and Validation. You’ll find myriad samples and delve into taking advantage of advanced features pre- sented by the API. Audience This book is designed for .NET developers who have experience with Visual Studio and database management basics. Prior experience with Entity Framework is beneficial but not required. The code samples in the book are written in C#, with some of these ix
  • 17.
    samples also expressedin Visual Basic. There are a number of online tools you can use to convert snippets of C# into Visual Basic. Contents of This Book This book contains nine chapters. Chapter 1, Introducing the DbContext API This chapter provides a high-level, end-to-end overview of the DbContext API. You’ll learn why the Entity Framework team decided to create the DbContext API and how it makes the Entity Framework easier to use. You’ll find example code, but there are no walkthroughs in this first chapter. Chapter 2, Querying with DbContext In this chapter you’ll learn about retrieving data from the database using Entity Framework’s query capabilities. You’ll learn how to find an entity based on its key and how to load all entities of a given type. You’ll learn how to use Language Integrated Query (LINQ) to sort and filter data. This chapter also explores the various strategies for loading related data. Chapter 3, Adding, Changing, and Deleting Entities Once you’ve learned how to query for data, this chapter will cover how to make changes to that data and save those changes to the database. You’ll see how to add new data as well as change and delete existing data. You’ll learn how Entity Frame- work keeps track of changes as you make them and how it saves them using the SaveChanges method. Chapter 4, Working with Disconnected Entities Including N-Tier Applications In this chapter, you’ll learn about using Entity Framework to persist changes that were made to entities while they were not being managed by a context. This chal- lenge is most common in N-Tier applications where a server component is re- sponsible for retrieving data and returning it to a client application. The client application then modifies this data and sends it back to the server to be saved. You’lllearnaboutvariousapproachestosolvingthischallengeandhowtheChange Tracker API can be used to implement them. Chapter 5, Change Tracker API The Change Tracker API is first introduced in Chapter 4 and this chapter is dedi- cated to exploring the remaining functionality of the change tracker. You’ll learn how to access the information that Entity Framework keeps about the state of your entity instances. You’ll also learn about the operations that can be performed from the Change Tracker API, including refreshing an entity from the database. This chapter wraps up with some examples of how the Change Tracker API can be used to solve some common application requirements. x | Preface
  • 18.
    Chapter 6, Validatingwith the Validation API Chapter 6 introduces the new Validation API that integrates with the DbContext and how it can be used to validate changes to your data before they are sent to the database. This chapter covers how the Validation API makes use of the existing validation functionality included in the .NET Framework. You’ll learn how vali- dation is integrated into the SaveChanges pipeline and how you can also trigger validation manually. You’ll learn how to set up validation rules and how to inspect validation errors when your data violates these rules. Chapter 7, Customizing Validations This chapter explores some more advanced features of the Validation API, which was introduced in Chapter 6. You’ll learn how to customize the logic used to val- idate entities, including customizing the logic that determines which entities need to be validated. These advanced techniques will allow you to write validation that interacts with the context, which opens up more validation possibilities, such as validating the uniqueness of a column. This chapter will also provide guidance regarding the dangers of using the Validation API for tasks other than validation. Chapter 8, Using DbContext in Advanced Scenarios Chapter 8 is devoted to covering some advanced functionality that’s available in the DbContext API. You’ll learn about techniques for unit testing and how to write tests that don’t hit a database. You’ll also see how to bypass Entity Framework’s query pipeline and interact directly with the database when the need arises. Should your requirements exceed what is possible from the DbContext API, you’ll see how to drop down to the underlying ObjectContext API. The chapter wraps up with a look at creating smaller bounded contexts that allow you to interact with a subset of your complete model. Chapter 9, What’s Coming Next for Entity Framework This book was written based on the features of the DbContext API available in the EntityFramework4.3release.Atthetimeofwriting,thereareanumberofpreviews available that demonstrate some of the features that the DbContext API will gain in upcoming releases. This chapter shares available information about these future releases. Conventions Used in This Book The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, and file extensions. Constant width Used for program listings, as well as within paragraphs to refer to program elements such as variable or function names, databases, data types, environment variables, statements, and keywords. Preface | xi
  • 19.
    Constant width bold Showscommands or other text that should be typed literally by the user. Constant width italic Shows text that should be replaced with user-supplied values or by values deter- mined by context. This icon signifies a tip, suggestion, or general note. This icon indicates a warning or caution. Using Code Examples This book is here to help you get your job done. In general, you may use the code in this book in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing a CD-ROM of examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission. We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN. For example: “Programming Entity Framework: DbCon- text by Julia Lerman and Rowan Miller (O’Reilly). Copyright 2012 Julia Lerman and Rowan Miller, 978-1-449-31296-1.” If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at permissions@oreilly.com. Safari® Books Online Safari Books Online (www.safaribooksonline.com) is an on-demand digital library that delivers expert content in both book and video form from the world’s leading authors in technology and business. Technology profes- sionals, software developers, web designers, and business and creative professionals use Safari Books Online as their primary resource for re- search, problem solving, learning, and certification training. xii | Preface
  • 20.
    Safari Books Onlineoffers a range of product mixes and pricing programs for organi- zations, government agencies, and individuals. Subscribers have access to thousands of books, training videos, and prepublication manuscripts in one fully searchable da- tabasefrompublisherslikeO’ReillyMedia,PrenticeHallProfessional,Addison-Wesley Professional, Microsoft Press, Sams, Que, Peachpit Press, Focal Press, Cisco Press, John Wiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FT Press, Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett, Course Tech- nology, and dozens more. For more information about Safari Books Online, please visit us online. How to Contact Us Please address comments and questions concerning this book to the publisher: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, CA 95472 800-998-9938 (in the United States or Canada) 707-829-0515 (international or local) 707-829-0104 (fax) We have a web page for this book, where we list errata, examples, and any additional information. You can access this page at: http://shop.oreilly.com/product/0636920022237.do To comment or ask technical questions about this book, send email to: bookquestions@oreilly.com For more information about our books, courses, conferences, and news, see our website at http://www.oreilly.com. Find us on Facebook: http://facebook.com/oreilly Follow us on Twitter: http://twitter.com/oreillymedia Watch us on YouTube: http://www.youtube.com/oreillymedia Acknowledgments We are grateful for the people who spent their precious free time reading through and even trying the walkthroughs in this book and providing feedback. Thanks to Rowan’s teammates, Arthur Vickers, Pawel Kadluczka, and Diego Vega, for their help in ensur- ing our accuracy throughout this book. Roland Civet, Mikael Eliasson, and Daniel Wertheim also provided invaluable feedback that helped us fine-tune our explanations and our code. Thanks to Microsoft for making it possible for Rowan to participate in this project. Preface | xiii
  • 21.
    Thanks once againto O’Reilly Media, especially our editors, Meghan Blanchette and Rachel Roumeliotis, for their support, their copyediting, and their extreme patience as many schedule conflicts delayed our promised deadlines. xiv | Preface
  • 22.
    CHAPTER 1 Introducing theDbContext API Since its first release, the most critical element in Entity Framework has been the ObjectContext. It is this class that allows us to interact with a database using a concep- tual model. The context lets us express and execute queries, track changes to objects and persist those changes back to the database. The ObjectContext class interacts with other important Entity Framework classes such as the ObjectSet, which enables set operations on our entities in memory, and ObjectQuery, which is the brains behind executing queries. All of these classes are replete with features and functionality—some of it complex and much of it only necessary for special cases. After two iterations of Entity Framework (in .NET 3.5 SP1 and .NET 4) it was clear that developers were most commonly using a subset of the features, and unfortunately, some of the tasks we needed to do most frequently were difficult to discover and code. Recognizing this, the Entity Framework team set out to make it easier for developers to access the most frequently used patterns for working with objects within Entity Framework. Their solution was a new set of classes that encapsulate this subset of ObjectContext features. These new classes use the ObjectContext behind the scenes, but developers can work with them without having to tangle with the ObjectContext unless they need to specifically use some of the more advanced features. The new set of classes was originally released as part of Entity Framework 4.1 (EF 4.1). The prominent classes in this simplified API surface are the DbContext, DbSet, and DbQuery. This entire package of new logic is referred to as the DbContext API. The new API contains more than just the DbContext class, but it is the DbContext that orchestrates all of the new features. The DbContext API is available in the EntityFramework.dll assembly, which also con- tains the logic that drives Entity Framework Code First. This assembly is separate from .NET and is even deployed separately as the EntityFramework NuGet package. A major portion of the Entity Framework is part of the .NET Framework (primarily System.Data.Entity.dll). The components that are included in .NET are considered the “core components” of Entity Framework. The DbContext API is completely dependent on these core components of Entity Framework. The Entity Framework team has 1
  • 23.
    indicated that theyare working to move more of these core components out of .NET and into the EntityFramework.dll assembly. This will allow them to deliver more fea- tures between releases of the .NET Framework. In Table 1-1, you can see a list of the high-level features and classes in the DbContext API, how they relate to the API surface from Entity Framework 4 (EF4), their general purpose, and their benefits. Table 1-1. Overview of DbContext API features DbContext API feature Relevant EF4 feature/class General purpose Benefit of DbContext API DbContext ObjectContext Represent a session with the database. Provide query, change tracking and save capabilities. Exposes and simplifies most commonly used features of Ob- jectContext. DbSet ObjectSet Providesetoperationsforentitytypes,suchasAdd, AttachandRemove.InheritsfromDbQuerytoexpose query capabilities. Exposes and simplifies most commonly used features of Ob- jectSet. DbQuery ObjectQuery Provide querying capabilities. The query functionality of DbQueryisexposedonDbSet,so you don’t have to interact with DbQuery directly. Change Tracker API ObjectCon- text.ObjectSta- teManager Get access to change tracking information and op- erations (e.g., original values, current values) man- aged by the context. Simpler and more intuitive API surface. Validation API n/a Provide automatic validation of data at the data layer.ThisAPItakesadvantageofvalidationfeatures already existing in .NET 4. New to DbContext API. Code First Model Building n/a Readsclassesandcode-basedconfigurationstobuild in-memorymodel,metadataandrelevantdatabase. New to DbContext API. Getting the DbContext API into Your Project The DbContext API is not released as part of the .NET Framework. In order to be more flexible (and frequent) with releasing new features to Code First and the DbContext API, the Entity Framework team distributes EntityFramework.dll through Microsoft’s NuGet distribution feature. NuGet allows you to add references to your .NET projects by pulling the relevant DLLs directly into your project from the Web. A Visual Studio extension called the Library Package Manager provides an easy way to pull the appro- priate assembly from the Web into your projects. Figure 1-1 displays a screenshot of the Library Package Manager being used to download and add the EntityFramework NuGet package into a project. 2 | Chapter 1: Introducing the DbContext API
  • 24.
    You can learnmore about using NuGet and the Library Package Man- ager at nuget.org. At the time of this book’s publication (early 2012), the current version of EntityFramework package is 4.3. Chapter 9 provides an overview of what to expect in future versions. Looking at Some Highlights of the DbContext API DbContext API is mostly targeted at simplifying your interaction with Entity Frame- work, both by reducing the number of methods and properties you need to wade through and by providing simpler ways to access commonly used tasks. In previous versions of Entity Framework, these tasks were often complicated to discover and code. We have a few favorites that act as great ambassadors to the new API, which we’ll share with you here. You’ll learn more about these as you work your way through the book. The samples used in this chapter are for explanation purposes only and not intended for you to perform in Visual Studio. Beginning with the next chapter, you’ll find walkthroughs that you can follow in Visual Studio. Figure 1-1. Getting EntityFramework.dll from the Library Package Manager Looking at Some Highlights of the DbContext API | 3
  • 25.
    Let’s start bylooking at how the DbContext API simplifies the context that we define and work with. We’ll compare the ObjectContext and DbContext based context classes from the model we’ll be using in this book, based on BreakAway Geek Adventure’s business applications. We’ll expose queryable sets of People, Destinations, and Trips based on a Person class, a Destination class, and a Trip class. Example 1-1 shows a subset of the BreakAwayContext class used in Entity Framework 4, based on an ObjectContext. It wraps up some known types into ObjectSets, which you can query against. Example 1-1. BreakAwayContext that inherits from ObjectContext public class BreakAwayContext : ObjectContext { private ObjectSet<Person> _ people; private ObjectSet<Destination> _destinations; private ObjectSet<Trip> _trips; public ObjectSet<Person> People { get { return _people ?? (_people = CreateObjectSet<Person>("People")); } } public ObjectSet< Destination > Contacts { get { return _ destinations?? (_destinations = CreateObjectSet< Destination >("Destinations")); } } public ObjectSet<Trip> Trips { get { return _ trips?? (_trips = CreateObjectSet<Trip>("Trips")); } } } Example 1-2 shows the same context and sets using a DbContext and DbSets instead. Already you can see a big improvement. You can use automatic properties with DbSet (that’s the simplified get;set; pattern), something you can’t do with ObjectSet. This makes for much cleaner code right out of the gate. There is a CreateDbSet method that’s relative to CreateObjectSet, but you aren’t required to use it for the purpose of creating a DbSet when you have no other logic to apply. Example 1-2. BreakAwayContext inheriting from DbContext public class BreakAwayContext : DbContext { public DbSet<Person> People { get; set; } public DbSet<Destination> Destinations { get; set; } public DbSet<Trip> Trips { get; set; } } 4 | Chapter 1: Introducing the DbContext API
  • 26.
    Reducing and SimplifyingWays to Work with a Set In Entity Framework 4, there are a number of tasks that you can achieve from both ObjectContext and ObjectSet. For example, when adding an object instance to a set, you can use ObjectContext.AddObject or ObjectSet.AddObject. When adding an object into the context, the context needs to know which set it belongs to. With ObjectContext.AddObject, you must specify the set using a string, for example: context.AddObject("Trips", newTrip); When ObjectSet was introduced in Entity Framework 4, it came with its own AddObject method. This path already provides knowledge of the set so you can simply pass in the object: context.Trips.AddObject(newTrip); With this new method available, the only reason ObjectContext.AddObject continued to exist in Entity Framework 4 was for backward compatibility with earlier versions. But developers who were not aware of this reason were confused by the fact that there were two options. Because the DbContext API is new, we don’t have to worry about backward compat- ibility, so the DbContext does not have a direct method for adding an object. Addition- ally, rather than providing the clunky AddObject method in DbSet, the method name is now simply Add: context.Trips.Add(newTrip); ObjectContext also has AttachObject and DeleteObject. DbContext does not have these methods either. DbSet has Attach and Remove, which are equivalent to ObjectSet’s Attach and Delete Object. You’ll learn more about interacting with DbSet beginning in Chapter 2. Retrieving an Entity Using ID with DbSet.Find One task that developers perform frequently is retrieving an entity by providing its key value. For example, you may have access to the PersonId value of a Person in a variable named _personId and would like to retrieve the relevant person data. Typically you would construct and execute a LINQ to Entities query. Here’s a query that uses the SingleOrDefault LINQ method to filter on PersonId when executing a query on context.People: context.People.SingleOrDefault(p => p.PersonId == _personId) Have you written that code so often that you finally wrote a wrapper method so you could pass the key value in and it would execute the LINQ query for you? Yeah, us too. Now DbSet has that shortcut built in with the Find method, which will return an entity whose key property matches the value passed into the method: context.People.Find(_personId) Looking at Some Highlights of the DbContext API | 5
  • 27.
    Find has anotherbenefit. While the SingleOrDefault query above will always query the database, Find will first check to see if that particular person is already in memory, being tracked by the context. If so, that’s what will be returned. If not, it will make the trip to the database. Under the covers, DbContext is executing logic on ObjectContext to perform the necessary tasks. You’ll learn more about DbSet.Find in Chapter 2. Avoiding Trolling Around the Guts of Entity Framework These are just a few examples of how much more natural it is to work with the DbCon- text API than the ObjectContext API. If you read Programming Entity Framework, 2e, you might be familiar with the many extension methods that Julie created and com- bined to simplify retrieving instances of objects that are being tracked by the context from the ObjectStateManager. One simple property, DbSet.Local, now performs that same task. In fact, thanks to the new Change Tracker API, there’s no need to dig into the ObjectStateManager. It’s not even part of the DbContext API. Instead you can use DbContext.Entry or DbContext.Entries to find and even change the information being tracked by the context. You’ll learn more about these methods in Chapter 5. Working with the BreakAway Model This book follows the model built around the BreakAway Geek Adventures company in the book Programming Entity Framework: Code First (O’Reilly). Even though the examples in this book use a model defined with Code First, the concepts apply just as well to a model built using the designer. Getting the Sample Solution If you want to follow along the book’s examples, you’ll need to download the starting solution from the download page of the book’s website at http://learnentityframework .com/downloads. In the solution you’ll find three projects: 1. The Model project contains the domain classes, which are configured using Data Annotations. 2. The DataAccess project contains the BreakAwayContext class that derives from DbContext. 3. The BreakAwayConsole project is a console application where you can add and execute methods as we explore the many capabilities of the DbContext API. When using Code First you begin with your classes. Code First uses convention to infer what the schema of the relevant database looks like and how Entity Framework can translate from your classes to that database. Code First’s conventions do not always align with your reality, however, so you can tweak how Code First maps your classes to the database by performing additional configuration. There are two ways to apply this additional configuration. One is by adding attributes to your classes and their 6 | Chapter 1: Introducing the DbContext API
  • 28.
    properties (called DataAnnotations) and the other is by using Code First’s Fluent API. In the Code First book, we showed you how to use both features and built up two versions of the BreakAway model—one that uses Data Annotations to configure the mappings and the other using the Fluent API. The examples in this book and the sample download are based on the version of the model that uses Data Annotations. For example, the first class you’ll encounter in Chapter 2 is the Destination class, which is displayed here in Example 1-3. Example 1-3. A class using Data Annotations to specify Code First configuration [Table("Locations", Schema = "baga")] public class Destination { public Destination() { this.Lodgings = new List<Lodging>(); } [Column("LocationID")] public int DestinationId { get; set; } [Required, Column("LocationName")] [MaxLength(200)] public string Name { get; set; } public string Country { get; set; } [MaxLength(500)] public string Description { get; set; } [Column(TypeName = "image")] public byte[] Photo { get; set; } public string TravelWarnings { get; set; } public string ClimateInfo { get; set; } public List<Lodging> Lodgings { get; set; } } The Destination class has a number of Data Annotations. It begins with a Table at- tribute indicating that the Destination class will map to a database table named Loca tions which has the schema baga. Without this annotation, Code First would presume the table name is the plural of Destination (Destinations), in the default dbo schema. The DestinationId property is configured to map to a column in the table named LocationId and the Name column to one called LocationName, with a max length of 200. The System.Data.SqlClient provider will default to specifying that the LocationName column is an nvarchar(200). Another annotation ensures that Code First understands that the Photo property maps to a column whose type is image. The BreakAway context class inherits from System.Data.Entity.DbContext, the central class of the DbContext API. It contains properties that reflect sets of the various model classes contained in the solutions. For example a property named Destinations returns a queryable set of Destination types. The queryable set comes in the form of a DbSet class—another piece of the DbContext API. Example 1-4 gives you a sampling of Working with the BreakAway Model | 7
  • 29.
    properties in theBreakAwayContext class, which you’ll see more of beginning with the next chapter. Example 1-4. A context class exposing three DbSets that wrap domain classes public class BreakAwayContext : DbContext { public DbSet<Destination> Destinations { get; set; } public DbSet<Lodging> Lodgings { get; set; } public DbSet<Trip> Trips { get; set; } } Code First can either create a database for you or be used to map to an existing database. By default, Code First will create a database for you on your local SQL Express instance, using the namespace-qualified context name as the name for the database. For the sake of simplicity, the examples in this book will let Code First create a database automat- ically. After running some of the sample code, you will find a DataAccess.BreakAway Context database on your local SQL Express instance. You can learn much more about Code First, its configurations, and its database interactions in Programming Entity Framework: Code First. Getting DbContext from an EDMX Model Although the book samples use Code First, you may not be using Code First to describe the model in your applications. If, instead, you are using the Entity Data Model De- signer and want to take advantage of the DbContext API, there’s an easy way to do that. Visual Studio uses the Text Template Transformation Toolkit (T4) generator to generate the default ObjectContext and classes from an EDMX file. The generator uses a default template, which is designed to create class fields in a particular way. With the default template, each entity in the model becomes a class that inherits from EntityOb ject and a separate class is generated to manage the entities that inherits from Object Context. Microsoft provides alternative templates that you can use to generate POCO classes and a DbContext-based context from the EDMX. These are available online and can easily be selected from within the Entity Data Model Designer: 1. Open your EDMX file in the Entity Data Model designer. 2. Right-click on the model background and select “Add Code Generation Item…” as shown in Figure 1-2. 3. In the Add New Item window, select “Online Templates” from the left menu and then search for “DbContext.” Select the DbContext Generator template from the search results, enter a name, and click “Add” (Figure 1-3). 8 | Chapter 1: Introducing the DbContext API
  • 30.
    As a result,two templates will be added to your project. One is a context template (Model.Context.tt in the sample shown in Figure 1-4), which generates a class that inherits from DbContext, shown in Example 1-5. Figure 1-2. Adding a new T4 template code generation item from the model’s context menu Figure 1-3. Selecting the DbContext Generator template Working with the BreakAway Model | 9
  • 31.
    Figure 1-4. Projectwith .tt template files and their code-generated .cs files Example 1-5. Generated BAEntities class inheriting from DbContext public partial class BAEntities : DbContext { public BAEntities() : base("name=BAEntities") { this.Configuration.LazyLoadingEnabled = false; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { throw new UnintentionalCodeFirstException(); } public DbSet<Activity> Activities { get; set; } public DbSet<Contact> Contacts { get; set; } public DbSet<CustomerType> CustomerTypes { get; set; } public DbSet<Equipment> EquipmentSet { get; set; } public DbSet<Trip> Trips { get; set; } public DbSet<Destination> Destinations { get; set; } public DbSet<Lodging> Lodgings { get; set; } 10 | Chapter 1: Introducing the DbContext API
  • 32.
    public DbSet<Payment> Payments{ get; set; } } The second template (also shown in Figure 1-4), here called Model.tt, is the one that generatesPOCOclassesforeachoftheentitiesinyourEDMXmodel.Asyousawabove, the context class exposes each of these POCO types in a DbSet. Using this template, you can take advantage of an existing visual model and still benefit from the DbContext API, which you’ll be learning about in this book. Ensuring DbContext Instances Get Disposed A DbContext (and its underlying ObjectContext) are responsible for managing and tracking changes to instances of the classes in its model. These classes are also respon- sible for managing a connection to the database. It’s important to ensure that any re- sources used to perform these operations are cleaned up when the DbContext instance is no longer needed. DbContext implements the standard .NET IDisposable interface, which includes a Dispose method that will release any such resources. The examples in this book will make use of the using pattern, which will take care of disposing the context when the using block completes (Example 1-6). If your applica- tion doesn’t make use of the using pattern, ensure that the Dispose method is called on any DbContext instances when they are no longer needed. Example 1-6. Instantiating and disposing a context with the using pattern public static List<Destination> GetDestinations() { using (var context = new BreakAwayContext()) { var query= from d in context.Destinations orderby d.Name select d; return query.ToList(); } } Ensuring DbContext Instances Get Disposed | 11
  • 34.
    CHAPTER 2 Querying withDbContext There are two things that almost every application that accesses a database has in com- mon: the need to retrieve data from the database and to save changes to that data back into the database. Over the next two chapters you will see how the DbContext API makes it easy to achieve these tasks using the Entity Framework. The focus of this chapter will be on retrieving data from the database. One of the great benefits of using an Object Relational Mapper (ORM), such as Entity Framework, is that once we have set up the mapping, we can interact with our data in terms of the objects and properties that make up our model, rather than tables and columns. When querying for objects, this means we no longer need to know how to write queries using the SQL syntax of our database. Writing Queries with LINQ to Entities Entity Framework queries are written using a .NET Framework feature known as Lan- guage Integrated Query, or LINQ for short. As the name suggests, LINQ is tightly integrated with the .NET programming experience and provides a strongly typed query language over your model. Strongly typed simply means that the query is defined using the classes and properties that make up your model. This provides a number of benefits such as compile-time checks to ensure your queries are valid and the ability to provide IntelliSense as you write your queries. LINQ is a general query framework and isn’t specific to Entity Framework, or even databases for that matter. A LINQ Provider is responsible for taking your LINQ query, translating it into a query against the data, and then returning results. For Entity Framework this provider is known as LINQ to Entities and is responsible for taking your LINQ query and translating it into a SQL query against the database you are targeting. The information you supplied to Entity Framework about the shape of your model and how it maps to the database is used to perform this translation. Once the query returns, Entity Framework is responsible for copying the data into instances of the classes that make up your model. 13
  • 35.
    The capabilities ofLINQ and its use within Entity Framework are beyond the scope of this book. This chapter will provide an overview to help you get up and running with queries using DbContext, but is not an exhaustive query guide. Programming Entity Framework, 2e, provides a much more in-depth look at the query capabilities of Entity Framework, not only in Chapter 3 and Chapter 4, which are dedicated to querying, but throughout the book. InadditiontoLINQ,EntityFrameworkalsosupportsatext-basedquery language known as Entity SQL, or ESQL for short. ESQL is typically used in more advanced scenarios where queries need to be dynamically constructed at runtime. Because ESQL is text-based, it is also useful in scenarios where the application needs to build a query against a model that isn’t known until runtime. Given that ESQL is less commonly used, it is not exposed directly on the DbContext API. If your application requires the use of ESQL, you will need to access the ObjectContext API using the IObjectContextAdapter interface. To follow along with the examples in this book you will need a Visual Studio solution containing a console application that references the BAGA model built in Programming Entity Framework: Code First. You can download a prebuilt solution from http://lear nentityframework.com/downloads. This prebuilt solution also includes a database ini- tializer that will reset the database and insert some seed data into the database each time you run the application. The seed data is used in the examples throughout this book. Code First Migrations Entity Framework 4.3 includes a new Code First Migrations feature that allows you to incrementally evolve the database schema as your model changes over time. For most developers, this is a big improvement over the database initializer options from the 4.1 and 4.2 releases that required you to manually update the database or drop and recreate it when your model changed. The prebuilt solution still makes use of the DropCreateDatabaseAlways initializer rather than using Code First Migrations. This allows us to ensure the database is reset to a well-known state before you run each example in this book. You can learn more about Code First Migrations at http://blogs.msdn.com/b/adonet/ archive/2012/02/09/ef-4-3-released.aspx. The Model project of the prebuilt solution contains classes that make up the BAGA domain model. The BAGA model includes a Destination class (Example 2-1) that rep- resents all the wonderful places that our intrepid travelers can venture to. 14 | Chapter 2: Querying with DbContext
  • 36.
    Example 2-1. Destinationclass as listed in download solution [Table("Locations", Schema = "baga")] public class Destination { public Destination() { this.Lodgings = new List<Lodging>(); } [Column("LocationID")] public int DestinationId { get; set; } [Required, Column("LocationName")] [MaxLength(200)] public string Name { get; set; } public string Country { get; set; } [MaxLength(500)] public string Description { get; set; } [Column(TypeName = "image")] public byte[] Photo { get; set; } public string TravelWarnings { get; set; } public string ClimateInfo { get; set; } public List<Lodging> Lodgings { get; set; } } The BAGA model also includes a Lodging class (Example 2-2) that represents the ac- commodation that is available at the various Destinations. Example 2-2. Lodging class as listed in download solution public class Lodging { public int LodgingId { get; set; } [Required] [MaxLength(200)] [MinLength(10)] public string Name { get; set; } public string Owner { get; set; } public decimal MilesFromNearestAirport { get; set; } [Column("destination_id")] public int DestinationId { get; set; } public Destination Destination { get; set; } public List<InternetSpecial> InternetSpecials { get; set; } public Nullable<int> PrimaryContactId { get; set; } [InverseProperty("PrimaryContactFor")] [ForeignKey("PrimaryContactId")] public Person PrimaryContact { get; set; } public Nullable<int> SecondaryContactId { get; set; } [InverseProperty("SecondaryContactFor")] [ForeignKey("SecondaryContactId")] public Person SecondaryContact { get; set; } } Writing Queries with LINQ to Entities | 15
  • 37.
    The Destination andLodging classes will be used extensively for the examples through- out this book. To perform data access using these classes you will be using the BreakA wayContext from the DataAccess project. The project contains additional classes that are represented in BreakAwayContext as well as the Lodgings and Destinations. We’ll be using Code First for the examples in this book, but the techniques you will learn apply to any context that derives from DbContext. This includes contexts created using the Model First or Database First workflows. Example 2-3. BreakAwayContext class as listed in download solution public class BreakAwayContext : DbContext { public DbSet<Destination> Destinations { get; set; } public DbSet<Lodging> Lodgings { get; set; } public DbSet<Trip> Trips { get; set; } public DbSet<Person> People { get; set; } public DbSet<Reservation> Reservations { get; set; } public DbSet<Payment> Payments { get; set; } public DbSet<Activity> Activities { get; set; } } Querying All the Data from a Set Arguably the simplest query you can write is one that fetches all the data for a given entity type. This is the equivalent of a SELECT * FROM mytable query in SQL. Fortunately you don’t need to know SQL, because Entity Framework will take care of translating LINQ queries into SQL for you. Getting all the data from a set doesn’t require you to really write a query. You can simply iterate over the contents of any given DbSet and Entity Framework will send a query to the database to find all the data in that set. Let’s add a PrintAllDestinations method to our console application that iterates over the Destinations set defined in our Break AwayContext and prints out the name of each Destination (Example 2-4). Example 2-4. Query for all destinations private static void PrintAllDestinations() { using (var context = new BreakAwayContext()) { foreach (var destination in context.Destinations) { Console.WriteLine(destination.Name); } } } 16 | Chapter 2: Querying with DbContext
  • 38.
    When you debugthe application, the console window will close when the application has finished executing, which may prevent you from inspectingtheoutput.Youcanputabreakpointattheendofthemethod for debugging. Alternatively, you can run without debugging (CTRL + F5), in which case Visual Studio will ensure that the console window remains open after the program has finished executing. If you update the Main method to call this new PrintAllDestinations method and run the application, you will see that the name of eachDestination in the database is printed to the console: Grand Canyon Hawaii Wine Glass Bay Great Barrier Reef As the code began iterating over the contents of the Destinations set, Entity Framework issued a SQL query against the database to load the required data: SELECT [Extent1].[LocationID] AS [LocationID], [Extent1].[LocationName] AS [LocationName], [Extent1].[Country] AS [Country], [Extent1].[Description] AS [Description], [Extent1].[Photo] AS [Photo] FROM [baga].[Locations] AS [Extent1] The SQL may not look like the SQL you would have written. This is because Entity Framework has a generic query building algorithm that not only caters to this very simple query, but also for much more complex scenarios. The query is sent to the database when the first result is requested by the application: that’s during the first iteration of the foreach loop. Entity Framework doesn’t pull back all the data at once, though. The query remains active and the results are read from the database as they are needed. By the time the foreach loop is completed, all the results have been read from the database. One important thing to note is that Entity Framework will query the database every time you trigger an iteration over the contents of a DbSet. This has performance impli- cations if you are continually querying the database for the same data. To avoid this, you can use a LINQ operator such as ToList to copy the results into a list. You can then iterate over the contents of this list multiple times without causing multiple trips to the database. Example 2-5 introduces a PrintAllDestinationsTwice method that demon- strates this approach. Example 2-5. Iterating all Destinations twice with one database query private static void PrintAllDestinationsTwice() { using (var context = new BreakAwayContext()) { Querying All the Data from a Set | 17
  • 39.
    var allDestinations =context.Destinations.ToList(); foreach (var destination in allDestinations) { Console.WriteLine(destination.Name); } foreach (var destination in allDestinations) { Console.WriteLine(destination.Name); } } } Because a query is sent to the database to find the items in a DbSet, iterating a DbSet will only contain items that exist in the database. Any objects that are sitting in memory waiting to be saved to the database will not be returned. To ensure added objects are included you can use the techniques described in “Querying Local Data” on page 24. Using LINQ for Sorting, Filtering, and More While this chapter will not be an exhaustive list of everything you can do with LINQ and Entity Framework, let’s take a look at the patterns used to achieve some common query tasks. Let’s say you want to print out the names of Destinations again, but this time you want them ordered alphabetically by Name. Add a new PrintAllDestinations Sorted method that uses a LINQ query to perform this sort (Example 2-6). Example 2-6. Query for destinations sorted by name private static void PrintAllDestinationsSorted() { using (var context = new BreakAwayContext()) { var query = from d in context.Destinations orderby d.Name select d; foreach (var destination in query) { Console.WriteLine(destination.Name); } } } The above code uses LINQ to create a query and then iterates the results of the query and displays the name of each destination. The query is expressed using a syntax that looks a little bit like SQL. You start by telling it what you want to select from (in our case, the Destinations set on our context). You give the set a name so that you can refer to it throughout the rest of the query (in our case that name is d). Following this, you 18 | Chapter 2: Querying with DbContext
  • 40.
    use operators suchas orderby, groupby, and where to define the query. Finally you spec- ify what you want returned using the select operator. In our case we want the actual Destination objectsreturned,sowespecifythenamethatwegavethesetinthefirstline. Remember that Entity Framework won’t execute the query against the database until it needs the first result. During the first iteration of the foreach loop, the query is sent to the database. The query remains active and each result is read from the database as it is needed by the application. LINQ also includes methods that will copy the results of a query into a collection. For example, ToList can be called on a query to copy the results into a new List<T>. Calling a method such as this will cause all the results to be retrieved from the database and be copied into the new List<T>. The code shown in Example 2-6 uses the LINQ query syntax to express the query. While most people find this the easiest to understand, there is an alternate method syntax that can be used if you prefer. Example 2-7 shows the same query expressed using method syntax. Example 2-7. LINQ method syntax in C# var query = context.Destinations .OrderBy(d => d.Name); The method syntax makes use of lambda expressions to define the query. The LINQ methods are strongly typed, which gives you IntelliSense and compile-time checking for the lambda expressions you write. For example, in the OrderBy method we are using a lambda expression to specify that we want to order by the Name property. You start a lambda expression by giving a name to the thing you are operating on; this forms the left side of the expression. In our case we are operating on a Destination and we have chosen to call it d. Then, on the right side of the expression, you specify the body of the expression. In our case we just want to identify the Name property. C# uses the lambda sign (=>) to separate the left and right sides of the expression. VB.NET uses the Function keyword followed by brackets to identify the left side of the expression. Example 2-8 shows the same query written in VB.NET using the method syntax. Example 2-8. LINQ method syntax in VB.NET context.Destinations.OrderBy(Function(d) d.Name) Another common task is to filter the results of a query. For example, we may only want Destinations from Australia. Add the PrintAustralianDestinations method shown in Example 2-9. Example 2-9. Query for Australian destinations private static void PrintAustralianDestinations() { using (var context = new BreakAwayContext()) { Using LINQ for Sorting, Filtering, and More | 19
  • 41.
    var query =from d in context.Destinations where d.Country == "Australia" select d; foreach (var destination in query) { Console.WriteLine(destination.Name); } } } This code looks very similar to the PrintAllDestinationsSorted we saw in Exam- ple 2-6, except we are using thewhere operator instead of orderby. You can also combine these operators. Example 2-10 shows how to query for Australian Destinations sorted by name. Example 2-10. Query combining filter and sort var query = from d in context.Destinations where d.Country == "Australia" orderby d.Name select d; Operators can also be combined in the method syntax. The same query from Exam- ple 2-10 is shown using method syntax in Example 2-11. Example 2-11. Method syntax for combining filter and sort var query = context.Destinations .Where(d => d.Country == "Australia") .OrderBy(d => d.Name); So far our queries have returned collections of entities from our model, but this may not always be the case. In fact, we have been returning complete Destination objects when we really only need the name. You can use projection to create a query that selects from a set of entities in your model but returns results that are of a different type. For example, you can use projection to create a query that selects from a set of entities type but only returns a subset of the properties of that entity. It’s called projection because you are projecting data from the shape of the source that you are selecting from onto the shape of the result set you want. In our case we want to project a query about Destinations into a result set that just has a string representing the destination’s name. Example 2-12 adds a PrintDestination NameOnly method that shows how we use the select section of our query to specify what we want the result set to contain. Example 2-12. Querying for just the Destination name private static void PrintDestinationNameOnly() { using (var context = new BreakAwayContext()) { 20 | Chapter 2: Querying with DbContext
  • 42.
    var query =from d in context.Destinations where d.Country == "Australia" orderby d.Name select d.Name; foreach (var name in query) { Console.WriteLine(name); } } } Example 2-13 shows how this same query can be written using method syntax by mak- ing use of the Select method. Example 2-13. Method syntax for projection var query = context.Destinations .Where(d => d.Country == "Australia") .OrderBy(d => d.Name) .Select(d => d.Name); LINQ is a powerful query language and this section has just grazed the surface of its capabilities. Programming Entity Framework, 2e, contains a much deeper look into using LINQ with the Entity Framework. There are also more example queries available in the Entity Framework MSDN documentation: http://msdn.microsoft.com/en-us/li brary/bb399367.aspx. Finding a Single Object So far you’ve seen queries that return a collection of entities, but sometimes you will want to run a query that just returns a single object. The most common scenario for querying for a single object is to find the object with a given key. The DbContext API makes this very simple by exposing a Find method on DbSet. Find accepts the value to be searched for and will return the corresponding object if it is found. If there is no entity with the provided key, Find will return null. One of the great things about Find is that it doesn’t unnecessarily query the database. It’s also capable of finding newly added objects that haven’t yet been saved to the database. Find uses a simple set of rules to locate the object (in order of precedence): 1. Look in memory for an existing entity that has been loaded from the database or attached to the context (you’ll learn more about attaching objects in Chapter 4). 2. Look at added objects that have not yet been saved to the database. 3. Look in the database for entities that have not yet been loaded into memory. To see this behavior, add the FindDestination method shown in Example 2-14. This method accepts an ID from the user and then attempts to locate the Destination with the specified ID. Finding a Single Object | 21
  • 43.
    Example 2-14. UsingFind to locate a Destination private static void FindDestination() { Console.Write("Enter id of Destination to find: "); var id = int.Parse(Console.ReadLine()); using (var context = new BreakAwayContext()) { var destination = context.Destinations.Find(id); if (destination == null) { Console.WriteLine("Destination not found!"); } else { Console.WriteLine(destination.Name); } } } The code above uses the Find method to look up the Destination with the specified ID. If one is found, it prints out the name of the destination. If Find returns null, indicating there is no Destination with the specified ID, an error message is displayed to the user. Find with Composite Keys Entity Framework supports entities that have composite keys, that is, entities where the key is made up of two or more properties. For example, you may have a Passport entity that uses a combination of IssuingCountry and PassportNumber as its key. To locate entities with a composite key you supply each of the key values to Find: context.Passports.Find("USA", "123456789") The key values must be supplied in the same order that they appear in the model. If you are using Model First or Database First, this is the order that they appear in the designer. When composite keys are used, Code First requires you to specify an order for them. You can use the Column annotation with the Order parameter to specify the order. If you are using the Fluent API, a HasKey call is required; the order of the key properties is the order they appear in the body of the HasKey call. There may be times when you want to query for a single object but are not able to use Find. These could include wanting to query by something other than the key or wanting to include related data in the query (as described in “Eager Loading” on page 33). To do this, you will need to create a standard LINQ query and then use the Single method to get a single object as the result. Let’s say we want to locate the Destination that has the name Great Barrier Reef. Name isn’t the key of Destination but we know there is, and only ever will be, one Great Barrier Reef. Example 2-10 introduces a FindGreatBarrierReef method that will locate this single Destination. 22 | Chapter 2: Querying with DbContext
  • 44.
    Example 2-15. Queryfor single entity based on name private static void FindGreatBarrierReef() { using (var context = new BreakAwayContext()) { var query = from d in context.Destinations where d.Name == "Great Barrier Reef" select d; var reef = query.Single(); Console.WriteLine(reef.Description); } } The LINQ query looks the same as any other query that filters based on name. We then use the Single method to let Entity Framework know that we expect a single result. If the query returns no results, or more than one result, an exception will be thrown. If there are potentially no matches, you can use the SingleOrDefault method, which will return null if no results are found. Example 2-16 shows the FindGreatBarrierReef method updated to account for the fact it may not exist in the database. Example 2-16. Query for single entity that may not exist private static void FindGreatBarrierReef() { using (var context = new BreakAwayContext()) { var query = from d in context.Destinations where d.Name == "Great Barrier Reef" select d; var reef = query.SingleOrDefault(); if (reef == null) { Console.WriteLine("Can't find the reef!"); } else { Console.WriteLine(reef.Description); } } } SingleOrDefault uses the same database query that Find uses when it looks for entities in the database. The SQL selects the TOP two results so that it can ensure there is only one match: SELECT TOP (2) [Extent1].[LocationID] AS [LocationID], [Extent1].[LocationName] AS [LocationName], [Extent1].[Country] AS [Country], Finding a Single Object | 23
  • 45.
    [Extent1].[Description] AS [Description], [Extent1].[Photo]AS [Photo], [Extent1].[TravelWarnings] AS [TravelWarnings], [Extent1].[ClimateInfo] AS [ClimateInfo] FROM [baga].[Locations] AS [Extent1] WHERE N'Great Barrier Reef' = [Extent1].[LocationName] If two rows are found, Single and SingleOrDefault will throw because there is not a single result. If you just want the first result, and aren’t concerned if there is more than one result, you can use First or FirstOrDefault. One important thing to remember is that LINQ queries against a DbSet always send a query to the database to find the data. So, if the Great Barrier Reef was a newly added Destination that hadn’t been saved to the database yet, the queries in Example 2-15 and Example 2-16 won’t be able to locate it. To look for newly added entities, you would also need to query the in-memory data using the techniques shown in “Querying Local Data” on page 24. Querying Local Data So far you’ve used LINQ to query a DbSet directly, which always results in a SQL query being sent to the database to load the data. You’ve also used the Find method, which will look for in-memory data before querying that database. Find will only query based on the key property though, and there may be times when you want to use a more complex query against data that is already in memory and being tracked by your DbContext. One of the reasons you may want to do this is to avoid sending multiple queries to the database when you know that all the data you need is already loaded into memory. Back in Example 2-5, we saw one way to do this was to use ToList to copy the results of a query into a list. While this works well if we are using the data within the same block of code, things get a little messy if we need to start passing that list around our application. For example, we might want to load all Destinations from the database when our application loads. Different areas of our application are then going to want to run different queries against that data. In some places we might want to display all Destinations, in others we might want to sort by Name, and in others we might want to filter by Country. Rather than passing around a list of Destination objects, we can take advantage of the fact that our context is tracking all the instances and query its local data. Another reason may be that you want the results to include newly added data, which doesn’t yet exist in the database. Using ToList on a LINQ query against a DbSet will always send a query to the database. This means that any new objects that don’t yet exist in the database won’t be included in the results. Local queries, however, will include newly created objects in the results. 24 | Chapter 2: Querying with DbContext
  • 46.
    The in-memory datafor a DbSet is available via the Local property. Local will return all the data that has been loaded from the database plus any newly added data. Any data that has been marked as deleted but hasn’t been deleted from the database yet will be filtered out for you. More information on how entities get into these different states is available in Chapter 3. Let’s start with the very simple task of finding out how many Destinations are in mem- ory and available to be queried. Go ahead and add the GetLocalDestinationCount method, as shown in Example 2-17. Example 2-17. Checking how many Destinations are in-memory private static void GetLocalDestinationCount() { using (var context = new BreakAwayContext()) { var count = context.Destinations.Local.Count; Console.WriteLine("Destinations in memory: {0}", count); } } The code accesses the Local property of the Destinations set that we created on our BreakAwayContext. Rather than running a query, we simply store the count in a variable and then print it to the console. If you run the application you will see that the count is zero: Destinations in memory: 0 We’re getting a zero count because we haven’t run any queries to load Destinations from the database, and we haven’t added any new Destination objects either. Let’s update the GetLocalDestinationCount method to query some data from the database before getting the local count (Example 2-18). Example 2-18. Checking in-memory data after a query private static void GetLocalDestinationCount() { using (var context = new BreakAwayContext()) { foreach (var destination in context.Destinations) { Console.WriteLine(destination.Name); } var count = context.Destinations.Local.Count; Console.WriteLine("Destinations in memory: {0}", count); } } This new code iterates over the Destinations set, causing the data to be loaded from the database. Because the data is loaded when we get the count from theLocal property, we now see a nonzero result when we run the application: Querying Local Data | 25
  • 47.
    Grand Canyon Hawaii Wine GlassBay Great Barrier Reef Destinations in memory: 4 Using the Load Method to Bring Data into Memory Iterating over the contents of a DbSet with a foreach loop is one way to get all the data into memory, but it’s a little inefficient to do that just for the sake of loading data. It’s also a little unclear what the intent of the code is, especially if the iteration code doesn’t directly precede the local query. Fortunately the DbContext API includes a Load method, which can be used on a DbSet to pull all the data from the database into memory. Go ahead and add the GetLo calDestinationCountWithLoad method (Example 2-19) that uses Load on the Destina tions set and then prints out the count of in-memory Destinations. Example 2-19. Using the Load to bring data into memory private static void GetLocalDestinationCountWithLoad() { using (var context = new BreakAwayContext()) { context.Destinations.Load(); var count = context.Destinations.Local.Count; Console.WriteLine("Destinations in memory: {0}", count); } } Compare this code with the GetLocalDestinationCount method we wrote back in Ex- ample 2-18. This updated code makes it much clearer that our intent is to load the contents of the Destinations set and then query the in-memory data. Load is actually an extension method on IQueryable<T> and is defined in the System.Data.Entity namespace. If you want to use Load, you will need to have this namespace imported. Because Load is an extension method on IQueryable<T>, we can also use it to load the results of a LINQ query into memory, rather than the entire contents of a set. For example, let’s say we only wanted to load Australian Destinations into memory and then run a few local queries on that subset of data. Let’s add the LoadAustralianDesti nations method shown in Example 2-20. Example 2-20. Loading results of a LINQ query into memory private static void LoadAustralianDestinations() { 26 | Chapter 2: Querying with DbContext
  • 48.
    using (var context= new BreakAwayContext()) { var query = from d in context.Destinations where d.Country == "Australia" select d; query.Load(); var count = context.Destinations.Local.Count; Console.WriteLine("Aussie destinations in memory: {0}", count); } } This time just the Destinations with Country set to Australia are loaded into memory. When we run the application, we see that the count we get from Local is reduced to reflect this. Using Load on a LINQ query will bring the results of that query into memory but it does not remove the results of previous queries. For ex- ample if you called Load on a query for Australian destinations and then Load on a query for American destinations, both Australian and Amer- ican destinations would be in memory and would be returned from Local. Running LINQ Queries Against Local So far we have just looked at getting the count from Local to make sure that it is re- turning the correct data that we brought into memory. Because Local is just a collection of in-memory objects, we can also run queries against it. One of the great things about LINQ is that it’s not specific to Entity Framework. We can use the same LINQ syntax to query a number of different data sources, including in-memory collections of objects. Let’s add a LocalLinqQueries method that pulls data into memory using a single data- base query and then runs some in-memory queries using Local (Example 2-21). Example 2-21. Using LINQ to query Local private static void LocalLinqQueries() { using (var context = new BreakAwayContext()) { context.Destinations.Load(); var sortedDestinations = from d in context.Destinations.Local orderby d.Name select d; Console.WriteLine("All Destinations:"); foreach (var destination in sortedDestinations) { Console.WriteLine(destination.Name); Querying Local Data | 27
  • 49.
    } var aussieDestinations =from d in context.Destinations.Local where d.Country == "Australia" select d; Console.WriteLine(); Console.WriteLine("Australian Destinations:"); foreach (var destination in aussieDestinations) { Console.WriteLine(destination.Name); } } } The code loads all Destinations into memory and then runs one query to sort them by Name and another to pull out just the Australian Destinations. Remember that Find also defaults to using in-memory data where possible. So we could also useFind and it would use the data we loaded rather than sending more queries to the database. While Load and Local are great if you want to reduce the number of queries that get run against the database just remember that pulling all your data into memory may be an expensive operation. If you are running multiple queries that only return a subset of your data you’ll probably get better performance by letting these queries hit the database and just pull back the data you actually need. Differences Between LINQ Providers There are a few subtle but important differences between querying directly against a DbSet and against Local. These two data sources actually use two different LINQ pro- viders. Querying against DbSet uses LINQ to Entities, which is specific to Entity Frame- work and uses your model and mapping to turn your query into SQL that is executed in the database. However, querying against Local uses LINQ to Objects, which per- forms filtering, sorting, and similar operations in memory using the standard .NET operators for testing equality, determining ordering, and the like. The same query syntax can return different results depending on which one you are using. For example, the database is typically not case-sensitive when comparing string values, but .NET is. If you issued a query for Destination names that contain “great”, the database would return “Great Barrier Reef” and “The great wall of China.” The same query against Local would return “The great wall of China” but would not return “Great Barrier Reef” because the capitalization of “great” is different. Most LINQ providers support the same core features, but there are some differences in features between each provider. For example, LINQ to Objects supports the Last operator but LINQ to Entities does not. Therefore, you can use Last when running queries against Local but not when running queries directly against a DbSet. 28 | Chapter 2: Querying with DbContext
  • 50.
    Working with theObservableCollection Returned by Local If you’ve looked at the API closely you may have noticed that Local returns an Observ ableCollection<TEntity>. This type of collection allows subscribers to be notified whenever objects are added or removed from the collection. ObservableCollection is useful in a number of data-binding scenarios, but it can also be useful if your application needs to know when new data comes into memory. Local will raise the CollectionChanged event whenever the contents of Local change. This can be when data is brought back from that database via a query, when new objects are added to the DbContext, or when objects previously brought into memory are marked for deletion. Let’s add a ListenToLocalChanges method that uses this functionality to log any changes to Destinations.Local to the console (Example 2-22). Example 2-22. Using CollectionChanged to print out changes to Local private static void ListenToLocalChanges() { using (var context = new BreakAwayContext()) { context.Destinations.Local .CollectionChanged += (sender, args) => { if (args.NewItems != null) { foreach (Destination item in args.NewItems) { Console.WriteLine("Added: " + item.Name); } } if (args.OldItems != null) { foreach (Destination item in args.OldItems) { Console.WriteLine("Removed: " + item.Name); } } }; context.Destinations.Load(); } } The code adds a new event handler to the Local collection of Destinations. This handler looks at items entering or leaving the collection and prints out the name of the affected Destination and indicates if it is being added or removed. Once the event handler is in place, we use Load to pull all the data from the database into memory. If you run the application, you can see the output appearing as items are returned from the database: Querying Local Data | 29
  • 51.
    Other documents randomlyhave different content
  • 54.
    The Project GutenbergeBook of The great illusion
  • 55.
    This ebook isfor the use of anyone anywhere in the United States and most other parts of the world at no cost and with almost no restrictions whatsoever. You may copy it, give it away or re-use it under the terms of the Project Gutenberg License included with this ebook or online at www.gutenberg.org. If you are not located in the United States, you will have to check the laws of the country where you are located before using this eBook. Title: The great illusion Author: Manly Banister Illustrator: Kelly Freas Release date: April 12, 2024 [eBook #73383] Language: English Original publication: New York, NY: Headline Publications, Inc, 1956 Credits: Greg Weeks, Mary Meehan and the Online Distributed Proofreading Team at http://www.pgdp.net *** START OF THE PROJECT GUTENBERG EBOOK THE GREAT ILLUSION ***
  • 57.
    THE GREAT ILLUSION ByMANLY BANNISTER illustrated by KELLY FREAS There was something phony about the whole set-up on that planet. Their culture was counterfeit. But why did they go to so much trouble to put on their act? [Transcriber's Note: This etext was produced from Super-Science Fiction February 1957. Extensive research did not uncover any evidence that the U.S. copyright on this publication was renewed.]
  • 58.
    Cliff Rowley's leanjowls beaded with sweat in the stagnant warmth of the tent. He tapped a bony finger on the camp table and glared at the communicator. "Clear out in a week! Why?" Commander Waldo Spliid's tired voice trickled from the communicator grid. Rowley would have appreciated video hook-up now. He wondered how Spliid's features portrayed his thoughts. "Here's final classification on Hume, Cliff. Category two X sub one." "Closed world!" Rowley groaned. "We've only been here three months!" "Eleven men in the field, Cliff. You're the odd ball. Everybody else is satisfied. Hume is only a step above savagery in culture. Top rating is satisfied. I don't like the conflicting picture of it, myself, but...." "Nor I," Rowley stabbed. The look in his hazel eyes hardened. "You wouldn't," Spliid said calmly, "even without seeing the reports. You're a percie, Cliff—our only psi-sensitive on Hume. But you've got to do a lot more than you've done yet to impress top rating. They're keener on the things you can't do than the things you can." "A few more months, Commander...." "A week, Cliff. Seven days. Get in and dig for all you're worth." "Me and my little psychic shovel," Rowley commented bitterly. A hum came out of the comm. Somewhere, far above the atmosphere of Hume, the Survey ship, with Spliid on board, cruised among the stars. "Clean up any questions you can," Spliid went on. "Bring your notes up to date. The pilot boat will pick you up ... let's see ... this is Wednesday ... Wednesday for us, anyway. Next Wednesday, then. Have everything ready to load. And keep on reporting."
  • 59.
    Rowley started toretort, thought better of it. He switched off the comm. Well, that did it. They'd had it, as far as Hume was concerned. And the puzzle still stared him in the face—him, Rowley, the boy who was going to do great things, like with teleconscious apprehension, with psychometry, with.... Psi-sensitives were new in the Galactic Ethnological Survey Corps— Galethsurv in the cryptic, telegraphic coding of service vernacular. Spliid had not been sarcastic when he had called Rowley a "percie", the abbreviated, half-humorous, half-scornful, scuttle-butt designation for the percipients. Percipiency was still too new in the ethnological service to evaluate. A percie had hunches and feelings he was supposed to follow. Sometimes, it seemed, a percipient vaulted completely over painful steps of reasoning and "cogged" a conclusion that was often correct. The ability could be valuable, if properly used. That's where Rowley's harness rubbed. His wasn't being used. He knew something was wrong on Hume. But if Galethsurv wanted to overlook his recommendation for further study, it should be no concern of his. But he couldn't run away from a problem that challenged him to solve it. Long grass swished against his calves as he strolled thoughtfully down toward the village of thatched, stone houses, bathed in the pink glow of a setting sun. Blue smoke curled lazily over stone chimneys, and even from this distance, he could hear the sharp, shrill voices of children raised in play. He took in the scene with a single glance, the stream running beside the village, the small, brown figures darting about the grassy lanes.
  • 60.
    The village wasnestled in a hollow of the rolling land. Beyond it and stalking around it to enclose it in a clasp of balsam, lay the great pine forest of Hume. Not really pine, but an other-world equivalent of it, each tree spaced a precise, geometrical distance from its neighbor, towering toward flecks of burnt-orange and mauve-colored clouds in the aquamarine sky. The forest of Hume was gigantic, mystifying. It challenged the mind. It covered the whole land surface of Hume with its geometrical spacing of trees. And the people who populated Hume called themselves Keepers of the Trees. Rowley tried to grasp the fact that what he saw here was almost endlessly repeated over the broad face of Hume. Why did he think that the real culture of Hume was otherwise than what he saw? A thousand thousand villages, purpling in the swift-rushing sunset ... a myriad of slender semi-savages, who spent their lives tending the trees. If he, Rowley, could perceive more than other men, then what did he perceive here? He wished he knew. What was the real culture? What lay behind this facade? Why did he think the impressions of his ordinary senses reported only the outward effect of a mere stage play? It was a mighty big play, performed for a very small audience—the eleven investigators for Galethsurv. How could he get to the bottom of the puzzle in the few days remaining, with no more guide than an inexplicable "feeling" of falseness? Time was so short! The illusion of reality in the village was strong enough to overwhelm him. Teramis was scratching in his garden while the light faded from the sky. He waved and called out to Rowley as he went by. Teramis had spent the day, with the rest of the villagers, among the trees, removing moss and insects, clipping dead branches ... why? Shy, big-eyed little kids, showing brown where they weren't clothed, ran in the grassy streets. Unusually—unnecessarily—clean for the offspring of a semi-savage people, he thought.
  • 61.
    Tsu was drawingwater from the creek as he came up. She paused, holding the water jar against youthful breasts, restrained under the taut fabric of her yellow sarong. Like others of her race, she was surpassingly slender, breathtakingly beautiful in the liquid melody of her movements. Her face was long, tanned, glowing with the ripeness of youth. Her eyes, long, tip-tilted, were lidded with mystery, and her black hair was substanceless shadow caressing her shoulders.
  • 62.
    It almost cameto him as he looked at her, greeted her. Did Tsu look the part of a shy, savage maiden of the wild? He had to admit that she did ... she looked like an over-enthusiastic video casting director's idea of category two X sub one maidenhood. The implications slipped from his mind as she clasped his hand. The warm flesh of her palm felt firm against his. An electric tingle wriggled up his arm. Not even the rigor of his emotional conditioning could have prevented that much. It was not good for field men to be bothered by emotions. It made their work difficult; they found wives on sub-standard worlds and wanted to bring them out to civilization; or, they reverted to the wilds themselves with their mates. The Corps conditioned its men against anything like that, so that emotional vagaries could not disturb the single-mindedness trained into them—to discover and interpret in the field. "Good evening, sintaha Rowley," Tsu said. He followed her into the house she shared with Smarin and Torl, her parents. They greeted Rowley warmly, slim, smiling, happy as usual. It was a stage play, performed for his benefit. He moved around among the actors, but he was not an actor himself. He was the audience. Rowley had been in this house often, always with a haunting sense of wrongness. He knew it as well as he knew his own tent. Living room, kitchen, two bedrooms and quarters for bathing. Clean people, the natives of Hume. Rowley sat on the stone stoop and contemplated the gathering shadows. Tsu came out and sat close beside him. He asked her again about the trees, why the people tended them. "It is proper to tend the trees, sintaha Rowley. We have done so always." Was she evading? Or did he fully understand her language, simple as it was? He had learned it quickly, and had wondered at the time
  • 63.
    that it wasso similar in grammar and syntax to his own. An odd coincidence—or deliberate casting, to impress the play more easily on the audience? "Tomorrow," he said, "I should like to learn more about the trees." "If it will please you," she said. Another sun was setting. Another day had gone to join the fruitless ones preceding it. The expedition among the trees had told him nothing. Everything was the same as Tsu had explained several times before. His alerted senses found no discrepancy. He was disappointed, and he said as much in his evening report to Commander Spliid. "It adds up," Spliid said encouragingly. Rowley felt a glow. "You get it?" "No, frankly. But top rating must have the right slant. Where does percipiency leave off and old fashioned imagination begin? You're functioning like a percie, even when there's nothing to perceive." "I thought you weren't satisfied...." "I'm not a percie, Cliff. Any dissatisfaction I may feel is aroused by the conflicting reports of the field men. Anyway, we can probably clear that up in the correlating department." Rowley's heart sank. "You are satisfied!" The speaker hummed. Spliid said, flatly, "I've got to be. Everybody else is ... except you." Rowley grunted. "Six days! I'll try to uncover something." Spliid's voice sounded worried. "I hate this, Cliff. Your talents can be valuable to the Corps. We deal in cubic parsecs of space and aeons
  • 64.
    of time. Ittakes more than ordinary reasoning power to cope with it." "I believe you mean it," Rowley said. "I do. So what's Hume? One world in millions." Rowley's switched him off. He bit his lip. It was Galethsurv's purpose to make single, cohesive sense out of the patch-work, and tatterdemalion shreds of human culture that had been systematically turned up in the galaxy. Where did the culture of Hume fit into that overall pattern? Galethsurv believed that the distribution of mankind among the stars had not been accident. Where, then, had Man originated? It was important to know. Remembrance of yesterday points the way toward a more highly educated guess about tomorrow. Someday, Man would find out if—or why—he had been deliberately seeded among the stars. And then...? "Sintaha Rowley, are you not also Keepers of the Trees on your own world?" Tsu was so earnest with the question, Rowley was surprised. He made a wry grimace, half humorous. "Of course, we grow trees for fruit, for shade and beauty, to cut down and make lumber for houses...." She drew away from him, rigid, trembling. "You cut down trees!" He hadn't meant to make that slip. He knew her feeling for trees. Her look accused him. "I don't understand your attitude," he said lamely.
  • 65.
    "Nor do Iunderstand yours." She brooded silently. "It is different, I suppose, on other worlds. The trees are different." They sat in the lush grass, on the hillside below his tent. The toy village lay at their feet, a cardboard set in miniature. "Your people puzzle us, Tsu. You are too different from us...." "We have tried to make it easy for you," she murmured. Easy? Too easy, he thought. It was all too plain, too easy to understand. That's why he couldn't understand a bit of it. "We hope," he went on, "that by studying your world and others like it, we may some day better understand the whole universe...." "Or reach a better understanding of your own thoughts?" She smiled. Her long eyes lidded heavily with amusement. "Wherever we go," he continued doggedly, "we find people like ourselves. Human beings. They are born; they grow up; they die. Human culture is built around the processes of living and dying. Our beliefs and actions stem from those facts—that we live and that we die. We are emotionally affected by them. Sometimes, we know great happiness. Then we remember that we die, and we suffer sorrow. I have seen no sadness in your village. Everybody is happy. It ... it isn't natural. I wonder how you would act if one of you were to die...." She stirred restlessly, movement restricted by her clinging sarong. "One of us will die for you," she said simply, "if you wish to study it." Sudden shock hammered at his brain. What a thing to say! What did she mean? Was she really as simple as her language seemed to indicate? He felt embarrassed. "Tsu, you know I didn't mean...." His eye caught a flicker of movement among the brown trunks of the trees. A slim figure left their shadow, picked its way uphill through
  • 66.
    the grasses, towardthem. Rowley recognized Smarin, Tsu's father. Smarin's slim ascetic face was expressionless, his long eyes hooded. "Torl fell from the tree," he said. "Torl is dead. Come, Tsu." Rowley felt hair prickle at the back of his neck. It seemed that Smarin had come out, strictly on cue. Then he realized that Smarin had meant it. The shock of a moment before intensified, expanded, pressurized itself into every cell of his brain. "Oh, no!" he said. Tsu got lithely up. She looked down at him, lips drawn, eyes lidded with slumbering sorrow. "It was your wish, sintaha Rowley. Come with us. Study and learn...." "It could have been an accident," Rowley reported over the comm, "but I have a feeling it was staged." "You saw the dead woman?" "She was dead, all right. They let me see that she was dead, then they buried her—at the foot of the tree. No ceremony. Shallow grave —not over a foot and a half deep." "Then what?" "Then they all went back to tending the trees. Tsu seemed happy as hell about the whole thing. She hoped I had learned what I wanted, she said." "I'm interested," Spliid broke in. "I'm coming down tonight, Cliff." "Where are you now?" "About a thousand miles east of you. I looked in on Stephans this afternoon. I'll get down there after dark."
  • 67.
    Sunsel glowed anarabesque of colors on the village at Rowley's feet. The comm was silent. He switched it off. Commander Waldo Spliid was a big, blond man. He bulked hugely at Rowley's side, among the intense shadows of the trees. Hume had no moon. Only the stars spattered a frail shine over the upper levels of the forest. Rowley said, softly, "Here's the grave." Spliid flashed a light, briefly. "What did they dig it with?" "Spade—shovel." "Steel blade?" "Iron, anyway. I reported on that I don't know where they get metals." Spliid flashed his light again, grunted. "No marker." Rowley nodded. "That's right. I thought about it at the time and wondered. I thought of mentioning it to Tsu. Know why I didn't?" Spliid grunted again. "I thought, if I did, somebody would come out of the trees, bringing a marker. Probably two sticks tied in a cross. Get what I mean?" "Gimme the shovel," said Spliid. Rowley handed him the collapsible entrenching tool he had been carrying. The Commander bent his back, scooped at the dirt. He worked swiftly, carefully, almost silently. "About eighteen inches deep, you said?" "About." Spliid fell to again. The metal blade chinked dully on moist clods. After a time, Spliid flashed his light again. His free hand entered the
  • 68.
    cone of yellowshine, prodded the moist dirt. He was on his knees, reaching far down into the hole he had dug. "I've gone by loose dirt," he puffed. "There's no body here, Cliff." "She was dead and I saw them bury her," Rowley insisted stubbornly. "Maybe hypnotism. I felt they were putting on a show for me. I keep asking myself why, and then I turn to the facts." "What facts?" "Why...." Rowley hesitated. "Hume has been classified a closed world. I think that's what they want. If this world had been uninhabited when Exploration turned it up, Colonisation would be surveying it now for settlement. If the population had a civilization above Class G, we'd be arranging to bring them up to the technological level of the rest of the galaxy. But we shut a two X sub one world away from contact with the galaxy to avoid disturbing the natural progress of the natives. How many thousands of years before Hume will be ready? Somehow, I feel they know more about us than we think they do ... and they're only too happy to be left to themselves." "Rubbish! Why?" "Why do they want it, or why do I think so? I don't know the answer either way. If you've ever seen a stage play, you'll understand what I mean. Everything about a stage play is phoney. You watch the play, knowing it isn't real. The scenery and backdrop are just painted imitations. All right—but the actions of the characters on the stage serve something like a catalyst. Your faculties of critical observation are suspended, and the play becomes real. For the time of the play, you are caught up in the illusion of reality that grips you. That's the way it is here on Hume. "You look around you in the broad light of day. You see a pastoral idyll. Everybody's happy. Everybody gets along with everybody else. All the people are beautiful, agreeable and kind. They have a simple culture, too far down the scale to admit to intercourse with the rest of the galaxy.
  • 69.
    "Look twice, though,and you see something else...." "All right," said Spliid. "Let's get back to camp." The sloping canvas top of Rowley's tent bulked dimly in the starlight. Spliid laid a heavy hand on Rowley's arm. "I've been thinking, Cliff. There was never a body in that grave." Rowley started. "Never was?" "Don't ask me. It's your idea, with talk of stage plays and phoney accidents. You made me feel it. I come down to find out. You've been the victim of something ... I don't know what. Are you comforted?" "No. If only we had more time!" "We've got a few days," Spliid reassured him. "You've got a good idea in that stage play simile. But the actors aren't very good, and the directing is abominable. It takes a lot of rehearsal to make a good play, Cliff." For a long time after the pilot boat drifted down from the upper air and whispered away toward the stars with Commander Spliid, Rowley stood brooding, looking down into the pool of shadows hiding the village. Stage play. Actors. What happens to the scenery when the audience goes home? Rowley shrugged and went to bed. In the morning, Rowley stirred together an unpalatable breakfast, then went down into the village. The natives were already stirring. Children ran in the grassy streets. The solid stone of the houses gleamed white and gray, streaked and spotted with brown, crumbling at the corners. The thatched roofs were ochre, glistening blue-grey with dew.
  • 70.
    Painted scenery? Theslender, racing children—hired extras? And Tsu —the leading lady? He felt miserable about disturbing Tsu and Smarin today. It was intrusion on their period of mourning. Did they mourn on Hume? There was nothing of mournful bereavement about the little stone house, gay in the sunshine, with its clustering border of purple, rose and yellow flowers. The inside was dark-brown dim, but he caught a glimpse of movement. He stepped to the door, leaned with his hand on the jamb, waiting to be noticed. "Sintaha Rowley! Good morning. Here is Tsu." Rowley dug his nails into the door post. Tsu came out skipping, but he was unaware of her. Torl ... Torl who was dead yesterday ... smiled at him and retreated into the interior. Tsu took his hand, brushing against him with her usual easy familiarity. He realized that his fingers trembled in her grip. He said, hoarsely, "That was Torl ... in there!" Tsu laughed up into his face, long eyes bright. "Why not? It is Torl's house, too!" "But ... but ... yesterday...." He couldn't bring himself to say that yesterday Torl had died and he had seen her buried. Tsu seemed to divine the thought in his mind. "Yesterday was yesterday, sintaha Rowley. Yesterday, Torl died, and you saw how it was. We hope you could make a good report of it." He was silent as they walked. He stole occasional glances at her, wondering. Somehow, the death and resurrection of Torl provided a key. His brain was swamped with conjecture.
  • 71.
    They left thevillage and climbed the hill. He had meant to sit with Tsu and Smarin, to share their grief a while this morning, if they would let him. Why he walked now, he could not say, save that his brain was in a whirl. And Tsu accompanied him gaily, chattering nonsense about the death of her mother. He stopped, looked at the village below. While they were here, he would ask Tsu for information about who lived where. He had already sketched the village from his tent. He would write in the information as an addition to his notes. A thought struck him. Why label the props on the stage set? Labels meant nothing ... unless you could see the set from the wings. It would help, if he could do that. "Let's sit here, Tsu," he said. She sat, obediently, among the tall grasses, folding slim, long legs under her like a child. He sat at her side, noting with relief that a slight hump in the slope hid the village from sight. He took her hand in his. "I have thought of something," he said carefully. "Tell me about the children. Let's take Yanek ... is that his name? He lives in the house next to you. How old is he?" She regarded him from the corners of her long eyes. "Old? Yanek is as old as a child. He is as old as he is." "How old is Yanek in years?" She hesitated, biting her lip in puzzlement. "There is always Yanek, sintaha Rowley. Why should there be anything about him of years?" She didn't know what he was talking about. Rowley felt excitement creep along the channels of his veins. "Can you remember when Yanek was born?" The look in her eyes made his heart pound harder. She was alarmed!
  • 72.
    He pressed on,relentlessly. "Yesterday, Torl died. Today, she lives. You do not understand a simple thing like age. You do not remember when Yanek was born, but he is not over seven or eight. Tsu ... tell me ... are you and your people immortal?" There was an anguish in his tone that made her drop her eyes. "No," she said, without moving her lips. That was the truth. His inner sense told him it was. And the truth was disappointing. What had he expected? The key to immortality? The Fountain of Youth? Men had sought it in ages past and never found it. His thoughts darted. "If you cannot remember Yanek being born, perhaps he was not born. Yet, you have families. There must be love...." "Love, yes! We love each other, we love our world, our trees...." "And if a young man loved you, Tsu, how would he say it?" His heart was pounding fiercely now. A fierce zeal possessed him that was not born of her nearness, the intimacy of their seclusion. His conditioning against emotional storms had been too thorough for him to break it now. It was something else that possessed him—the excitement of the hunter viewing the first, sparse tracks of the game he seeks. He had asked. It all depended now on her answer, for the mystery was coming clear to him. Her long eyes were heavy-lidded, candid, without guile. "How would he among your people, sintaha Rowley?" He thought, wildly, she doesn't know! He thought, she is inexperienced. He thought again, she would never know, unless...." He slipped an arm around her bare shoulders and drew her to him. "Like this," he said, looking down into her tip-tilted eyes. Then he kissed her. Her sarong slipped....
  • 73.
    "I am unhappywith you, Cliff," Commander Spliid said with chilly formality. Rowley leaned back in his chair in Spliid's office aboard the Survey ship. Spliid laid his pipe in the tray on his desk. He said, "What happened to your daily reports?" Rowley stuffed his own pipe, lit it. "I thought you knew. I didn't make any." Spliid's look of exasperation wavered and dimmed through the swirls of blue smoke. It was all over now, and Rowley felt no sense of hurry. Hume was a pinpoint of light in the star-carpeted vestibules of space behind them. In another hour, they would shift into overdrive. Hume would vanish from their lives forever. "I assume," he said, "that Hume is now officially closed." Spliid nodded. He fixed questioning gray eyes on Rowley. "Good," said Rowley. "That's the way it will always be." "Always?" Spliid fumbled with his pipe. "For our life-times, maybe...." "Always," Rowley repeated. He drew on his pipe, enjoying the luxury of keeping the Commander's curiosity at bay. "Human beings have no place on Hume. I found that out the day after you dropped in on me. That's why I made no reports. I just sat around, waiting for the pilot boat." Spliid held a lighter to the dark-stained bowl of his pipe. "So you're satisfied now, too?" Rowley nodded noncommittally. "At first," he said distantly, "I imagined crazy things—like a super-advanced race living underground, giving us the bum's rush with a play-show they had rigged up." "And you found out you were wrong," suggested Spliid. "I found out I was partly right."
  • 74.
    "I won't buysupermen living in caves, Cliff." "Neither would I. The next crazy thing I thought was that the natives were immortals and they didn't want us to share in it. Silly, huh?" "Pretty silly," Spliid agreed drily. "I knew they wanted to get rid of us," Rowley went on earnestly. "I could feel it. But why? Most inferior races we run against want contact with the galaxy...." "They want refrigerators and washing machines, tractors, railroad trains and automobiles," Spliid interrupted. "If we gave them, their culture would go to pot in a generation. There's a reason for our methods." "A lot of little things about Hume didn't jibe," Rowley continued. "Bathrooms, for instance." "No bathrooms on Hume?" Spliid grinned. "Bath rooms, yes. Just bathing went on in there. And outside, where the little house in back ought to be ... nothing." Rowley tamped the ashes in his pipe, withdrew a blackened finger. "We take that sort of thing for granted, you know. We assume proper facilities are around someplace and don't give them a second thought. They weren't present in the stage setting because they weren't needed." "Come, now...!" "Fact. Another fact: grass growing in the streets. The way those kids played on it, it would have been worn away in a week. Slim evidence, but it's part of the picture." "What I'm interested in," said Spliid, "is the death. Did you learn what they did with the body?" "You were right," Rowley said. "There wasn't any. I saw Torl the next day, alive and kicking. That's what put me off on the immortality
  • 75.
    tangent." Spliid grunted. "Anotheract in the play?" "Yes, and badly directed. The director didn't understand death as we do." Spliid shook himself. "Now, wait...!" "Honest and truly. How do we think of death—most of us? We believe in somehow living on after death takes place—immortality of the soul. Can you visualize how a stage director who didn't understand that concept would cast it?" "What do you think I am, a percie? Get on with it." "Consider this, then. I gambled with my emotional adjustment conditioning. There was one angle I hadn't exploited, because of that conditioning. Sex." "If you are trying to tell me you unloaded the conditioning we give you," Spliid interrupted, "I won't believe it!" "No—I wouldn't. But, in the interest of ethnological investigation, I could grab a kiss. So I did." "I see," drily. "Not yet, you don't. I got no reaction. Like embracing a tree. Anyway, I kissed her. Somehow...." He hesitated. "Her garment...." "No wonder you made no report," growled Spliid. "Believe me, Cliff, I'm going to have that conditioning process looked into!" Rowley laughed, briefly. "No need for that. It's sound. You'll be interested in what that slipping garment revealed." "Another time, another place...." "I saw a perfect, living statue!" Spliid's eyes alerted. "A what?" Spliid relaxed. "I think I know what you mean. Go on."
  • 76.
    Rowley drew heavilyon his pipe. A brooding look shadowed his lean face. "I learned about Yanek then. I learned about Tsu and Smarin and Torl and all the rest of them. If we weren't such damned prudes, Commander, and I had flipped a sarong sooner, we'd have found everything out long ago. You've heard about the sinner who was told he could remain in Heaven only on condition he could pick Adam out of the crowd? He chose the only man he could find ... without a navel." "Maybe they lay eggs," Spliid suggested. "Oviparous." Rowley gave him a look of humorous scorn. "Do statues lay eggs?" Spliid's expression cleared. "By God! Now I really understand you!" "The natives of Hume couldn't reproduce in any manner. Naturally, I wanted to know why. And the answer came to me—protective coloration ... camouflage!" "Apparent. Camouflage for what?" "You've heard the expression, if you can't lick 'em, join 'em...?" "Sure, but...." "But suppose you can't join 'em, either?" Rowley laughed, excitedly. "You make like something they want to protect!... Know anything about dryads, Commander?" Spliid snorted. "Supernatural creatures that live in trees? Dryads don't exist!" "Neither do the people of Hume." Spliid looked at him in such a way Rowley felt his sanity was being weighed.
  • 77.
    "Suppose you werea native of Hume, and some alien beings came along. You could read their minds. You'd know right off they wouldn't recognize you as a life-form like themselves. They might move right in and destroy you without knowing it, and you would be unable to defend yourself. That was actually the situation on Hume, and we were the aliens. So the natives pretended they were a type of life-form we want to protect." "How was it done?" Spliid wanted to know. "Mental projection. After the directors of the play read our minds, they tried to reproduce what they found there. They slipped on the points I mentioned, because those things meant little or nothing to them. But they were enough to rob the play of its semblance of reality. "Tsu, Smarin, Torl ... even the village itself ... were all imaginary— not something we thought we saw, but solidified mental projections of the thoughts the natives had gleaned from our minds." "I'm just beginning to see the real value of your talents, Cliff." "Thanks," Rowley acknowledged briefly. "If we have the right to exclude inferior cultures from contact with us, a superior culture must certainly have an equal right to exclude us from contact with theirs." Spliid wagged his head, half smiling. His pipe had gone out and he puffed at it without effect. "I've been waiting for you to tell me who these 'directors' are," he said. Rowley grinned. "You won't believe this. The directors needed something to keep their play actors busy ... some logical occupation of their time. What could they find more logical—to them—than taking care of trees? Because the directors themselves are the trees —the living, intelligent forest of Hume. Fantastic, isn't it?" Spliid sighed as if deeply gratified.
  • 78.
    "If it weren'tfor one thing even more so, I'd say it was the most fantastic thing I ever heard of." "What's more fantastic than intelligent trees?" "Human beings," said Spliid. THE END
  • 79.
    *** END OFTHE PROJECT GUTENBERG EBOOK THE GREAT ILLUSION *** Updated editions will replace the previous one—the old editions will be renamed. Creating the works from print editions not protected by U.S. copyright law means that no one owns a United States copyright in these works, so the Foundation (and you!) can copy and distribute it in the United States without permission and without paying copyright royalties. Special rules, set forth in the General Terms of Use part of this license, apply to copying and distributing Project Gutenberg™ electronic works to protect the PROJECT GUTENBERG™ concept and trademark. Project Gutenberg is a registered trademark, and may not be used if you charge for an eBook, except by following the terms of the trademark license, including paying royalties for use of the Project Gutenberg trademark. If you do not charge anything for copies of this eBook, complying with the trademark license is very easy. You may use this eBook for nearly any purpose such as creation of derivative works, reports, performances and research. Project Gutenberg eBooks may be modified and printed and given away—you may do practically ANYTHING in the United States with eBooks not protected by U.S. copyright law. Redistribution is subject to the trademark license, especially commercial redistribution. START: FULL LICENSE
  • 80.
    THE FULL PROJECTGUTENBERG LICENSE
  • 81.
    PLEASE READ THISBEFORE YOU DISTRIBUTE OR USE THIS WORK To protect the Project Gutenberg™ mission of promoting the free distribution of electronic works, by using or distributing this work (or any other work associated in any way with the phrase “Project Gutenberg”), you agree to comply with all the terms of the Full Project Gutenberg™ License available with this file or online at www.gutenberg.org/license. Section 1. General Terms of Use and Redistributing Project Gutenberg™ electronic works 1.A. By reading or using any part of this Project Gutenberg™ electronic work, you indicate that you have read, understand, agree to and accept all the terms of this license and intellectual property (trademark/copyright) agreement. If you do not agree to abide by all the terms of this agreement, you must cease using and return or destroy all copies of Project Gutenberg™ electronic works in your possession. If you paid a fee for obtaining a copy of or access to a Project Gutenberg™ electronic work and you do not agree to be bound by the terms of this agreement, you may obtain a refund from the person or entity to whom you paid the fee as set forth in paragraph 1.E.8. 1.B. “Project Gutenberg” is a registered trademark. It may only be used on or associated in any way with an electronic work by people who agree to be bound by the terms of this agreement. There are a few things that you can do with most Project Gutenberg™ electronic works even without complying with the full terms of this agreement. See paragraph 1.C below. There are a lot of things you can do with Project Gutenberg™ electronic works if you follow the terms of this agreement and help preserve free future access to Project Gutenberg™ electronic works. See paragraph 1.E below.
  • 82.
    Welcome to ourwebsite – the ideal destination for book lovers and knowledge seekers. With a mission to inspire endlessly, we offer a vast collection of books, ranging from classic literary works to specialized publications, self-development books, and children's literature. Each book is a new journey of discovery, expanding knowledge and enriching the soul of the reade Our website is not just a platform for buying books, but a bridge connecting readers to the timeless values of culture and wisdom. With an elegant, user-friendly interface and an intelligent search system, we are committed to providing a quick and convenient shopping experience. Additionally, our special promotions and home delivery services ensure that you save time and fully enjoy the joy of reading. Let us accompany you on the journey of exploring knowledge and personal growth! ebookultra.com