0% found this document useful (0 votes)
805 views759 pages

Devforce Reference

The document provides an overview of the EntityManager class in DevForce, which acts as a gateway between the client and server. It handles communication with the application server through queries and saves. The EntityManager caches entities locally and supports a variety of query types to retrieve entities from the server or cache. It saves changed entities to the server and updates the local cache accordingly.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
805 views759 pages

Devforce Reference

The document provides an overview of the EntityManager class in DevForce, which acts as a gateway between the client and server. It handles communication with the application server through queries and saves. The EntityManager caches entities locally and supports a variety of query types to retrieve entities from the server or cache. It saves changed entities to the server and updates the local cache accordingly.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

EntityManager

Last modified on March 23, 2011 22:14


Contents
EntityManager overview
What next?
The EntityManager is the client gateway to the server. The EntityManager typically handles
all client communications with the application server. Queries and saves are the most
common operations. The EntityManager is the most heavily used DevForce class and its
presence is felt on almost every page of the documentation. This topic offers a technical
introduction to the EntityManager: how to create one, how to use it, and the capabilities it
offers.


EntityManager overview
The EntityManager serves three main functions:
1. Communicate with the application server
2. Query and save entities
3. Hold entities in a local container called the entity cache.
When the client code of a DevForce application requires data or other external services, it
typically calls a member of an EntityManager object. Nothing prevents you from calling
external services directly. But it is usually easier and safer to route those requests through an
EntityManager. The EntityManager (assisted by helper components) establishes
communication channels, sets up the client's security context, serializes and deserializes data,
and regulates the application-level flow of traffic with the application server.
The EntityServer is its correspondent on the application server. The EntityServer screens and
interprets requests coming from EntityManagers, translating them into the appropriate
operations on the server.
Query and save requests are the predominant EntityManager activities. The EntityManager
can login, logout, connect, disconnect, and invoke selected methods for execution on the
server. But mostly it trades in queries and saves and the entity data exchanged in those two
operations.
You can ask the EntityManager to query for entities in a wide variety of ways:
with LINQ queries
o
by EntityKey

with Entity SQL (ESQL)
with stored procedure queries
by navigating from one entity to another (e.g., aCustomer.Orders)
However you do it, EntityManager puts the queried entity results in its entity cache. When
you create new entities, you add them to that cache. When you delete entities, you are actually
marking entities in the cache, scheduling them to be deleted. The inner workings of changing
entities in cache is covered under Create, modify and delete.
When you eventually ask the EntityManager to save, it finds the changed entities in cache -
the ones you've modified, added, and scheduled for deletion - and sends their data to the
EntityServer. If all goes well, the EntityServer reports success and the EntityManager adjusts
the cached entities to reflect the save by discarding deleted entities and re-setting the
EntityState of the added and modified entities to Unchanged.



















EntityManager by task
This page categories the public API of the EntityManager class by task type. The types of
tasks largely parallel the high-level organization seen in the DevForce development tree-view.


This topic strives to be a birds-eye view of the EntityManager API from the perspective of
some trying to grasp the scope and purpose of this, the most important and largest class in
DevForce.
To that end, the API is presented in a task-oriented fashion, with API member categorized
into major functional areas. For example, you will find the query-oriented members gathered
together under the "Query" section. This affords a better appreciation of the scope and variety
of query operations than you might obtain otherwise by sifting an alphabetical list of class
members.
This is not a definitive list or description of EntityManager features. Only the API
documentation for EntityManager is authoritative in that respect. The point of this topic is to
orient you to the possibilities.
To that end, most of the public members of the EntityManager class are mentioned and
receive a sentence or two of explanation.
Note: the terms "manager" and "EntityManager" are interchangeable here as they are almost
everywhere in DevForce documentation.
Configure
The EntityManager members with which to configure a new EntityManager and learn about
its current configuration. Constructors have been omitted.
A few members you can set or attach to:
Member Summary
AuthorizedThreadId Get and set the id of the thread on which this manager can run
EntityManagerCreated
Static event raised whenever a new EntityManager is created. Useful
for tracking and uniformly configuring the managers created in
multiple EntityManager scenarios
EntityServerError
Event raised when the EntityServer returns an exception for any
reason
Tag
Get and set an arbitrary object. Useful for distinguishing one manager
from another in multiple EntityManager scenarios
UseAsyncNavigation
Get and set whether property navigations that must retrieve related
entities from the server will "lazy load" asynchronously. It is always
true for a Silverlight EntityManager because all server requests must
be asynchronous; you cannot set this value in Silverlight. It is false by
default in full .NET environments where "lazy loads" tend to be
performed synchronously but you can change it to true.
VerifierEngine
Get and set the DevForce validation engine (the validation-discover)
assigned to this manager. This is the validation engine used by
automatic property validation within a cached entity.
Most of the configuration members you can only read:
Member Summary
CompositionContext
Gets the CompositionContext instance that helps determine how
MEF will compose some of the components that support this
manager, a key part of the DevForce extensibilty story. You
establish the manager's CompositionContext when you
construct it.
DataSourceExtension
Get the string that identifies the data source targeted by this
manager. You set the manager's DataSourceExtension when
you construct it.
DataSourceResolver
Get a wealth of information about the data sources used by this
manager. That environment is named in the manager's
DataSourceExtension.
EntityServiceOption
The enumeration indicating whether the manager connects to a
remote service (n-Tier), a local service (2-tier) or can connect to
both a local and remote service. You establish the manager's
EntityServiceOption when you construct it.
IsClient
Whether the manager is running on a client or on the server.
The valus is usually true - meaning the manager is running on
the client - but a number of processes on the server are provided
with a server-side EntityManager; the EntityServer interceptor
classes and your custom remote service methods are good
examples. The value would be false for these server-side
EntityManagers.
IsEntityType Get if the supplied type is known to be an entity type.
MetadataStore
Get the application-wide EntityMetadataStore, the store of
metadata about all currently known entity types in the
application.
Options Get the EntityManagerOptions, a miscellaneous bag.
UsesDistributedEntityService
Get whether this EntityManager communicates with a remote
server as it must for a Silverlight EntityManager. It is false for
2-tier deployments.
Query
The EntityManager members related to querying entities, either from remote data sources or
from its entity cache.
Many of the members that can fetch entities from the server come in both synchronous and
asynchronous versions. The asynchronous versions can be used on any client EntityManager.
The synchronous versions are only available for regular .NET clients and also can be used by
custom server methods calling into a server-side EntityManager. You cannot use (or even see)
these synchronous methods on a Silverlight EntityManager.
Members that read exclusively from the entity cache are always synchronous and are
available to all EntityManagers, including Silverlight EntityManagers.
Member Summary
ExecuteQuery
Synchronously executes its IEntityQuery query
argument, returning an untyped IEnumerable of entities.
Not available in Silverlight.
ExecuteQuery<T>
Synchronously executes its strongly typed
IEntityQuery<T> query argument, returning an
IEnumerable<T> of T-type entities. Not available in
Silverlight.
ExecuteQueryAsync
Executes asynchronously its IEntityQuery query
argument. An untyped IEnumerable of entities is
returned in the completed event args.
ExecuteQueryAsync<T>
Executes asynchronously its strongly typed
IEntityQuery<T> query argument. , An
IEnumerable<T> of "T" entities is returned in the
completed event args.
ExecuteQueryForObject
Synchronously executes its IEntityQuery query
argument, returning a single, untyped object such as a
count or the first entity that satisfies the query criteria.
Not available in Silverlight.
ExecuteQueryForObjectAsync<T>
Executes asynchronously its strongly-typed
IEntityQuery<T> query argument. A a single, untyped
object, such as an integer count or the first entity that
satisfies the query criteria, is returned in the completed
event args.
FindEntities<T>
Searches the entity cache for entities of type "T" which
also have an entitystate that matches one of the flag
values in the EntityState argument.
FindEntities
Searches the entity cache for all entities whose
entitystate matches one of the flag values the EntityState
argument. Can optionally limit the search to entities of a
specified type.
FindEntity
Searches the entity cache for an entity with a given
EntityKey. By default the search would not return a
deleted entity with that key but you can indicate with a
boolean flag that you want the entity if it is deleted.
FindEntityGraph
Searches the entity cache for the entity "roots" passed as
arguments to the method and also returns the entities
related to those root entities. The "entity graph" is the
combination of a root and its related entities. The extent
of the graph is defined by the relationships identified in
the EntitySpan argument.
GetNullEntity<T>
Get the "null entity" (aka, the "nullo") for the entity type
"T" that represents the "entity not found". Reference
navigation from an entity-in-cache (e.g.,
anOrder.Customer) returns the "nullo" rather than null if
the entity can't be found.
GetNullEntity The untyped variant of GetNullEntity<T>.
GetQuery<T>
Returns an EntityQuery<T> that, if executed, would
query for all entities of type "T". The statement,
manager.GetEntity<Customer>()), returns a query that,
if executed, would retrieve all customers in the database.
It is typically the foundation query to which the
developer adds filter clauses to narrow the search.
RefetchEntities
Refreshes the entities identified in the method arguments
with the most recent data available from the database. A
synchronous method that is not available in Silverlight.
RefetchEntitiesAsync
The asynchronous version of RefetchEntities that is
available in Silverlight.
Some EntityManager members notify subscribers about query activity.
Member Summary
Querying
A cancellable event raised when the manager is about to process a query. The
manager has not yet determined if it will satisfy the query from its entity cache
or will have to go to the server for entities. It is raised before Fetching.
OnQuerying
The virtual method that a derived EntityManager can override to raise the
Querying event.
Fetching
A cancellable event raised when the manager, while processing a query, has
determined that it must go to the server for entities. It is raised before sending a
query to the server. It won't be raised if the manager expects to satisfy the query
entirely from its entity cache. Compare to Querying.
OnFetching
The virtual method that a derived EntityManager can override to raise the
Fetching event.
Queried
An event raised by the manager after it has processed a query request
successfully; not raised if the query failed. The query may or may not have
fetched data from the server. If it did, the event is raised after entities were
retrieved successfully and merged into the entity cache. The EventArgs can tell
you whether the query involved a trip to the server and, if so, which of the
entities retrieved from the server (including related entities) resulted in changes
to the entity cache.
OnQueried
The virtual method that a derived EntityManager can override to raise the
Queried event.
Finally, a few query-control members.
Member Summary
CancelAsync
Cancel a pending asynchronous query. Actually not just for canceling
queries. It can cancel any unfinished asynchronous operation but it is
most often used to cancel queries.
DefaultQueryStrategy
Get and set the QueryStrategy the manager should use if the query
itself does not specify a QueryStrategy.
QueryCache
Get the manager's QueryCache, the special cache that remembers
previously issued queries. The manager may decide to fulfill a new
query request entirely from its entity cache if the manager finds the
query in its QueryCache. Adding and removing queries from the
QueryCache is largely automatic but you can manipulate it directly
once you gain access to it through this property.
Save
The EntityManager members related to saving cached entities with pending changes
Member Summary
HasChanges
Get whether the manager's entity cache contains a changed entity. More
specifically whether the entitystate of any cached entity is other than
Unchanged.
SaveChanges
Save synchronously all changed entities in cache. Overloads accept
optional parameters such as callback delegate, SaveOptions, and a caller-
defined "user-state" object to keep track of and differentiate individual
save calls. The returned SaveResult provides information about success
or failure and the entities that were saved. Because synchronous, it is not
available in Silverlight.
SaveChanges
(entities, ...)
A SaveChanges variant that saves just the entities specified in the
argument
SaveChangesAsync
Save asynchronously all changed entities in cache. Same overloads as
SaveChange. Because asynchronous, the completed event args provide
information about success or failure and the entities that were saved. This
method is available on all .NET clients, including Silverlight.
SaveChangesAsync
(entities, ...)
A SaveChangesAsync variant that saves just the entities specified in the
argument
Some EntityManager members notify subscribers about save activity.
Member Summary
Saving
A cancellable event raised when the manager is about to save. The manager
provides the handler with a list of entities it intends to save.
OnSaving
The virtual method that a derived EntityManager can override to raise the Saving
event.
Saved
A cancellable event raised when the manager has saved successfully; not raised if
the save failed. The event args provide information about success or failure and the
entities that were saved.
OnSaved
The virtual method that a derived EntityManager can override to raise the Saved
event.
Finally, a few save-control members.
Member Summary
DefaultSaveOptions Get and set the SaveOptions that regulate the save unless the
SaveChanges caller submits substitute SaveOptions.
ForceIdFixup
Immediately replace the temporary ids of newly-created entities with
server-generated permanent ids for entities whose keys are generated by
a custom method. The save process performs this "fix-up" automatically
but you can force it to happen sooner. Because synchronous, it is not
available in Silverlight.
ForceIdFixupAsync
The asynchronous version of ForceIdFixup available on all .NET
clients including Silverlight.
Access the entity cache
Some EntityManager members yield insights into the manager's entity cache.
Member Summary
IsEntityLoaded(key) Whether an entity with given EntityKey is in the manager's cache.
CacheStateManager
Get the manager's CacheStateManager through which you can save and
restore a copy of the entity cache in the form of an EntityCacheState.
GetEntityGroup,T>
Get the EntityGroup inside the cache that holds the cached instances of
type "T".
GetEntityGroup
The non-generic version of GetEntityGroup<T> takes the entity type as
a parameter.
GetEntityGroups
Get an array of all EntityGroups in the cache. There will be a group for
every type the cache has ever seen.
Many operations move entities into and out of a manager's entity cache automatically. You
can manipulate this cache directly using these EntityManager members.
Member Summary
AddEntities
Add entities to the cache as if they were new, Added entities that do not
exist in the database and will be inserted if saved.
AddEntity
Add an entity to the cache as if it were a new, Added entity that does not
exist in the database and will be inserted if saved.
AttachEntities
Attach entities to the cache as if they were pre-existing, Unchanged
entities that might have been queried from the database.
AttachEntity
Attach an entity to the cache as if it were a pre-existing, Unchanged
entity that might have been queried from the database.
Clear
Clear the cache, emptying it of all entities. Also clears the QueryCache
described in the Query section above.
Cleared Event raised when Clear is called.
RemoveEntities
(entityState, ...)
Remove all entities with the given entitystate, optionally clearing the
QueryCache (the default)
RemoveEntities
(entities, ...)
Remove the entities in the argument, optionally clearing the QueryCache
(the default).
RemoveEntities
(entityType,
entityState)
Remove entities of a particular and entitystate, optionally clearing the
QueryCache (the default).
RemoveEntity Remove the entity, optionally clearing the QueryCache (the default).
ImportEntities
Import shallow copies of the entities into the cache, merging them
according to the provided MergeStrategy.
Create, modify and delete
These methods assist the developer in the course of creating, modifying and deleting entities.
Member Summary
AcceptChanges
Treat all entities with pending changes as if they had been saved. They
should appear as if they had been freshly retrieved from the database.
Added and Modified entities become Unchanged, their current version
values overwrite their original version values. Deleted entities are removed
from cache, becoming Detached.
RejectChanges
Rollback all entities with pending changes. They should appear as if they
had been freshly retrieved from the database. Deleted and Modified entities
become Unchanged, their current version values restored from their
original version values. Added entities are removed from cache, becoming
Detached.
CreateEntity<T>
Create new entity of type "T"; the entity remains detached although the
entity retains the inaccessible memory of the manager that created it.
CreateEntity
Create an entity dynamically with this non-geneneric version of
CreateEntity.
EntityChanging
Cancellable event raised when a cached entity is about to change, e.g., an
entity is about to be added, modified, attached, queried, imported, deleted,
detached, committed or rolled back.
EntityChanged
Event raised when a cached entity has changed, e.g., an entity was added,
modified, attached, queried, imported, deleted, deEtached, committed or
rolled back.
GenerateId
Generate a temporary id for a newly created entity that requires custom Id
generation; that temp id becomes permanent during save as result of an id
fix-up process.
Secure
We devote a full topic to security elsewhere. In brief, all DevForce EntityManager instances
must have acquired a local security context before performing most server operations. The
manager may acquire that context implicitly (as when relying upon cookie-based security) or
explicitly with some of these EntityManager methods.
Member Summary
IsLoggedIn Get whether this manager is currently authenticated.
LinkForAuthentication
Link this manager's security context to that of the source
EntityManager passed as a parameter. Enables multiple
EntityManagers to share the security context of a single master
EntityManager that can login and logout on their behalf.
Login Login (authenticate) synchronously with the server using the supplied
credentials. Not available in Silverlight because synchronous.
LoginAsync
The asynchronous variant of Login, available on all client
technologies.
Logout
Logout (de-authenticate) synchronously with the server. The server
will not accept new requests from this manager until it logs-in again.
Not available in Silverlight because synchronous.
LogoutAsync
The asynchronous variant of Logout, available on all client
technologies.
Principal
Get the IPrincipal instance that identifies the current user and his/her
roles. The concrete instance is often a richer, custom IPrincipal
implementation such as a derivative of the DevForce UserBase class.
Miscellaneous server calls
The EntityManager can be the applications sole channel for all communications with the
server. Most communications concern data. Security commands were covered above. Other
kinds of server communications are addressed by the following members.
Connectivity
By default, the EntityManager automatically and immediately tries to connect to the server
upon construction. But you may have to connect and disconnect for a variety of reasons with a
method listed here:
Member Summary
Connect
Connect to the server explicitly and synchronously. Not available in
Silverlight because synchronous.
ConnectAsync
Connect to the server explicitly asynchronously. Available on all client
platforms.
Disconnect Disconnect the manager deliberately and continue running offline.
IsConnected Get whether this manager believes it is connected to the server.
Remote Service Method
The client may call a custom application method on the application server using one of these
two Invoke... methods. These methods are untyped, affording the developer the ultimate
luxury of sending almost anything as parameters and receiving almost any kind of result. The
developer should consider wrapping these commands in a type-safe manner before exposing
them to higher level application layers.
Member Summary
InvokeServerMethod
Call a remote server method synchronously, passing in optional
service method parameters of any type. The parameters must be
both serializable and understood by the server method.
InvokeServerMethod returns the object result that was itself
returned by the remote server method. The client may cast the
result or otherwise interpret it as best it can. Not available in
Silverlight because synchronous.
InvokeServerMethodAsync
The asynchronous variant of InvokeServerMethod, available on
all .NET clients. Because it is asynchronous, the value returned by
the remote service method becomes accessible on the client in the
callback's event args.
Push notification
Two asynchronous members are involved in the server notification service (aka, Push).
Member Summary
RegisterCallback
Register a callback method with notification service on the server, include a
userToken and pass in optional service parameters. The callback gets called
with each notification until it is cancelled.
CancelCallback
Unsubscribe to the notification service by cancelling the callback via its
associated userToken

















Create an EntityManager
Last modified on April 20, 2011 10:29
Construct a bare EntityManager
Call "new" to construct a new instance of the EntityManager class. It can be as simple as
C# manager = new EntityManager();
VB manager = New EntityManager()
That manager is ready to use with any entity class model available. This default constructor
assumes that you want to contact the server as soon as possible and starts connecting
immediately (asynchronously in Silverlight).
You won't be able to do anything with the manager until you've established a security context
for the EntityManager. That isn't readily apparent out-of-the-box because DevForce grants all
users full access rights; you can use the newly created EntityManager to query and save
without doing anything.
You are sure to impose authentication constraints of some sort and when you do, the
EntityManager will refuse to send any messages to the server until those constraints are met.
Please establish your security plan early in the development process.
Construct the EntityManager for your entity model
The entity model you created using the Entity Data Model Designer also generated a custom
EntityManager for you, one that derives from the DevForce EntityManager class and is
enriched with additional members that make it easier to work with your entity model.
Peek inside the generated code file (e.g., NorthwindIBEntitiesIB.Designer.cs). Notice the
custom EntityManager near the top of the file. It might looks a bit like this:
C#
IbEm.DataSourceKeyName(@"NorthwindEntities")]
public partial class NorthwindEntities : IbEm.EntityManager {
// ..
}
VB
<IbEm.DataSourceKeyName("NorthwindEntities")>
Partial Public Class NorthwindEntities
Inherits IbEm.EntityManager
' ..
End Class
You can construct one of these as you did the bare DevForce EntityManager.
C# manager = new NorthwindEntities();
VB manager = New NorthwindEntities()
Look further in the generated code to find several constructors that enable you to determine
initial characteristics of the EntityManager. The first is the constructor you called above; all of
its parameters are optional.
C#
public NorthwindManager(
bool shouldConnect=true, // Whether to start connecting to the server immediately
string dataSourceExtension=null, // optional target environment
IbEm.EntityServiceOption
entityServiceOption=IbEm.EntityServiceOption.UseDefaultService,
string compositionContextName=null)
: base(shouldConnect, dataSourceExtension, entityServiceOption,
compositionContextName) {}
VB
Public Sub New(Optional ByVal _
shouldConnect As Boolean =True, _
Optional ByVal dataSourceExtension As String =Nothing, _
Optional ByVal entityServiceOption As IbEm.EntityServiceOption
=IbEm.EntityServiceOption.UseDefaultService, _
Optional ByVal compositionContextName As String =Nothing)

MyBase.New(shouldConnect, dataSourceExtension, entityServiceOption,
compositionContextName)
End Sub
Another generated constructor gathers all options together into an
EntityManagerContext. The EntityManagerContext allows for additional settings not
available in the other constructors, including options to control refetch behavior and connect
to a non-default application server.
C#
public NorthwindManager(
IbEm.EntityManagerContext entityManagerContext) : base(entityManagerContext) {}
VB
Public Sub New(ByVal entityManagerContext As IbEm.EntityManagerContext)
MyBase.New(entityManagerContext)
End Sub
These constructors are available for the base EntityManager class too. You can read the
DevForce API documentation for details about these parameters and the other constructors.
You might consider a brief digression now to learn about creating a disconnected
EntityManager and creating EntityManagers that target different databases under different
execution scenarios.
Custom EntityQuery properties
The custom EntityQuery properties are one reason you may prefer to create a new custom
EntityManager such as NorthwindEntities rather than a bare-bones EntityManager.
Peeking again at the generated code for NorthwindEntities we find query properties generated
for each of the entity types. Here is one for querying Customers.
C#
public IbEm.EntityQuery<Customer> Customers {
get { return new IbEm.EntityQuery<Customer>("Customers", this); } // IbEm ==
IdeaBlade.EntityModel
}
VB
Public ReadOnly Property Customers() As IbEm.EntityQuery(Of Customer)
Get ' IbEm == IdeaBlade.EntityModel
Return New IbEm.EntityQuery(Of Customer)("Customers", Me)
End Get
End Property
It's a nice touch - a bit of syntactic sugar - that can make a LINQ query a little easier for
developers to read and write:
C#
query1 = northwindManager.Customer.Where(...);
query2 = bareManager.GetQuery<Customer>().Where(...);
VB
query1 = northwindManager.Customer.Where(...)
query2 = bareManager.GetQuery(Of Customer)().Where(...)
The two queries are functionally the same. Most developers prefer query1.
















The EntityManager is not thread-safe
The EntityManager is not thread-safe and neither are entities. An EntityManager throws an
exception if you try to use it on multiple threads.
This topic touches upon the challenges and risks of cross-threading and describes how you
use the AuthorizedThreadId to control which thread an EntityManager calls home.


Thread mischief
Question: Why did the multithreaded chicken cross the road?
Answer: other to side. To the get.
IdeaBlade used to receive desperate support calls about applications that used to work but
have suddenly begun behaving erratically under real user loads.
The application would occasionally return seemingly impossible results. An entity might say
it was unmodifed when it actually had changes. Entities would mysteriously disappear from
lists or appear in lists where they should not. Such errors didn't show up in testing. They
appeared in production or during stress testing ... not predictably but occasionally.
"Are you using the EntityManager in multiple threads?" we would ask? "No" was the usual
reply. But, upon further investigation, sure enough, someone had referenced the
EntityManager - or one of its entities - on another thread.
Today the EntityManager throws an exception if you call one of its members on more than
one thread. You get news of your mistake early, during development, while you are calm and
have time to fix it.
The EntityManager is not thread-safe
The EntityManager is not thread-safe.
The RIA Services DomainContext, the Entity Framework ObjectContext, and the NHibernate
Session classes aren't thread-safe either.
Internally the EntityManager maintains mutable collections of mutable objects. That is in the
very nature of entities and of the components with which you manage them. They cannot be
made thread safe.
You may think you need to write background tasks to improve performance. You generally do
not. The EntityManager can perform many operations asynchronously for you.
Perhaps you want to retrieve several large entity collections in background. You can launch
multiple asynchronous queries from a single EntityManager running on the main thread;
DevForce will handle the background threading and marshal the results back to the main
thread safely. See the topic on asynchronous queries.
AuthorizedThreadId and the EntityManager's home thread
An EntityManager remembers the id of the thread on which it was created. This identifies its
home thread.
The EntityManager's AuthorizedThreadId property tells you what thread id that is.
You won't care about this id as long as you stay clear of multi-threaded scenarios.
Unfortunately, some times you can't. Two scenarios come to mind:
1. Automated MS Tests of asynchronous queries
2. ASP.NET clients that maintain an EntityManager across requests.
In both cases, the EntityManager can be called on a thread other than the thread on which it
was created. That is usually a big, red "danger" flag. It turns out to be safe in these "free
threading" scenarios because the EntityManager will never be called on its original thread
again.
Of course the EntityManager doesn't know that. It will throw an exception (see below) when
called on the new thread, because it assumes the worst and fears that concurrent multi-
threaded access may occur. We have to tell it that its home thread has changed which we do
by setting its AuthorizedThreadId property to the id of the new thread. Here's how to set the
AuthorizedThreadId to the currently executing thread:
C#
manager.AuthorizedThreadId =
System.Threading.Thread.CurrentThread.ManagedThreadId;
VB
manager.AuthorizedThreadId =
System.Threading.Thread.CurrentThread.ManagedThreadId
A moment ago you read: "the EntityManager will never be called on its original thread
again."
We recommend that you be deeply suspicious of any such claim. You may trust ... but you
should verify.
Fortunately, you get that verification for free when you change the AuthorizedThreadId. If
something calls upon the EntityManager back on the original thread, the EntityManager will
throw an exception ... because the original thread is no longer the home thread. Let's try it.
C#
// Now executing on original thread with Id=18
// Change the home ThreadId to a phoney
manager.AuthorizedThreadId = 1234;

// Call the EntityManager on thread Id=18
Manager.Customers.ExecuteAsync(); // Throws exception
VB
' Now executing on original thread with Id=18
' Change the home ThreadId to a phoney
manager.AuthorizedThreadId = 1234

' Call the EntityManager on thread Id=18
Manager.Customers.ExecuteAsync() ' Throws exception
ExecuteAsync throws an exception:
Customers query failed with exception: System.InvalidOperationException: An
EntityManager can only execute on a single thread. This EntityManager is authorized to
execute on the thread with id=1234; the requested operation came from the thread with
Id=18. ...
EntityManagers on ASP Clients
In most cases, an ASP.NET web application developers should create a new EntityManager
for each request.
However, when writing a "wizard" that carries user data forward from request to request,
some developers choose to hold an EntityManager in an in-memory Session variable. That
way, they can reuse cached entities across requests rather than have to struggle with managing
temporary storage for changed entities.
There are other, perhaps safer and more scalable ways, to address this scenario.
In essence, you store the EntityManager in Session just before the current request ends; when
the follow-up request begins, you pull the EntityManager instance out of Session and assign it
to your manager variable.
This will fail. The follow-on-request is on a different thread than the prior request. The
EntityManager you put into Session is pinned to the thread of the prior request. It will throw
the System.InvalidOperationException the moment you use it on the new request.
The solution is as described above. Set the AuthorizedThreadId property to the new request's
thread immediately after restoring the EntityManager from Session, well before calling any
other of its members.
Disabling thread id checking
You can disable thread id checking by setting AuthorizeThreadId to null.
This option exists for backward compatibility with earlier versions of DevForce. We can't
think of a good reason to use it. It is especially dangerous in server methods which may be
called by multiple threads.
Please only disable thread id checking for a very good reason and with full awareness of the
risks.
Entities are not thread safe either
The EntityManager throws an exception when exercised on multiple threads. Unfortunately,
there is no similar guard logic for entities nor for collections of entities. You have to ensure
that they are used in a thread-safe manner.
As mentioned, it is best to avoid multiple threads in the first place. You rarely need
background threads in a client application. Regard claims to the contrary with deep suspicion.
Server programming is another matter. Strive to make custom server logic single-threaded.
Avoid stateful static classes. When multiple threads are unavoidable, make sure you use the
necessary synchronization logic.
Avoid multi-threaded programming
Multi-threaded, concurrent programming is a deep and difficult topic beyond the scope of
DevForce documentation. It really is "brain surgery".
Experts agree:
1. Design so you don't need multiple threaded code
2. Hire and learn from an expert unless you are an expert
3. Don't write it alone; scrutinize mult-threaded code with a partner
4. Attack that code with automated tests.

















Create an offline EntityManager
You may want to create an offline EntityManager during testing and development or to run
the application when disconnected from the network and database.
The most frequently used EntityManager constructor is declared like this:
C#
public EntityManager(
bool shouldConnect=true, // Whether to start connecting to the server immediately
string dataSourceExtension=null,
IbEm.EntityServiceOption
entityServiceOption=IbEm.EntityServiceOption.UseDefaultService,
string compositionContextName=null);
VB
Public Sub New( _
Optional ByVal shouldConnect As Boolean =True, _
Optional ByVal dataSourceExtension As String =Nothing, _
Optional ByVal entityServiceOption As IbEm.EntityServiceOption
=IbEm.EntityServiceOption.UseDefaultService, _
Optional ByVal compositionContextName As String =Nothing)
End Sub
All of the parameters are optional. The parameter of interest in this topic is shouldConnect
which is true by default. That means that the manager automatically starts connecting to the
EntityServer.
You'll probably do just that in production. But you might want to set it false.
Maybe your application doesn't have a connection to the server at right now. Maybe the user
has launched the application while several miles high on an airplane. You could design the
application to run disconnected until a network connection can physically be established.
Maybe the application shouldn't connect at all during this session. Many automated tests
require the presence of an EntityManager, perhaps one populated with test entities. They don't
need - and don't want - to talk to the server or the database. That would only make the tests
slower and vulnerable to interrupted connections and disabled databases.
Many programmers run disconnected when running the application in development for the
same reasons; there might not even be a database in the early stages of development.
Of course you won't be able to save changes while disconnected. Fortunately, most automated
tests don't need to save and the savvy developer can easily divert save requests while in
development mode.
You can create a disconnected EntityManager like this:
C#
manager = new NorthwindEntities(shouldConnect: false);
// ...
manager.ConnectAsync(connectCallback); // Time to connect
VB manager = New NorthwindEntities(shouldConnect:= False)
' ...
manager.ConnectAsync(connectCallback) ' Time to connect


























Reconnect an offline EntityManager
This topic covers how an EntityManager can lose its connection to the server and reconnect
later.


Connected by default
By default, an EntityManager automatically and immediately tries to connect to the server
upon construction; ordinarily you do not have to initiate a connection explicitly.
Becoming disconnected
Various circumstances may cause an EntityManager to become disconnected.
1. You deliberately create an offline manager.
2. You decide to take the manager offline by calling its Disconnect method.
3. The application loses its connection to the server as it began a server operation or in
the midst of a server operation.
In all three cases, the EntityManager enters a disconnected state, a fact easily determined by
accessing its IsConnected property.
The IsConnected property reports whether the manager "believes" it is connected to the
EntityServer. It may "think" it is connected when, in fact, it could not reach the server if it
tried.
Losing the connection
The application decided to disconnect in examples #1 and #2. In the 3rd example, the
application loses the connection involuntarily and without warning.
The EntityManager responds by setting itself in the disconnected state and then prepares to
throw an EntityServerConnectionException. You can (and should) be ready to intercept and
handle that exception by attaching a handler to the manager's EntityServerError event.
See the the topic devoted to handling the EntityServerError event.
Your handler next decides how to proceed. Rather than shut down, you may choose to tell the
rest of the application about the problem and continue running in a well-defined offline mode.
Anticipating connectivity problems
It is wise to listen to the .NET event that announces the gain and loss of network connectivity.
The requisite event differs from one client platform to the next but there always is such an
event.
However, do not depend upon it to reflect the true and complete state of affairs. A flakey
connection could break in the middle of an attempt to connect. The network connection may
be good but the middle tier server could be down. The EntityManager will disconnect and
prepare to throw an exception whatever the cause. You can glean the details from the
exception in the body of the EntityServerErrorEventArgs .
Your application could lose contact with the server at any time. Plan for it. Remember to
handle the EntityServerError event if you want your application to survive a disconnection or
if you prefer to shutdown gracefully.
Restore the connection
An EntityManager will not reconnect spontaneously. Once offline, it stays offline until you
reconnect explicitly. A DevForce application with a well-stocked entity cache can operate
offline effectively for a long time, albeit with limited functionality.
Your application must decide when to try to reconnect. It may decide to try again if a .NET
event signals restored network access, or a retry timer fires, or in response to a user action.
Whatever the trigger, your code must call the EntityManager's Connect or
ConnectAsync methods; only the async method is available in Silverlight.
As always, code defensively and be prepared for connectivity failures.















Target different databases dynamically

You can target different databases dynamically by creating the EntityManager with a non-
default DataSourceExtension.


The need for different data source targets
When you start writing an application, you probably only have one database, your
development database.
That won't last long. Eventually, the application will query and save to one database during
development, and to other databases in your staging, test, and production environments. That's
four different database instances (all with the same schema one hopes). You need some way
to switch among these databases depending upon which the environment you want to be in.
You may put the "switch" in a configuration file on the client. You might determine it
programmatically on the client. Either way, the client application should be able acquire the
value of the switch and choose the appropriate server environment.
Let's generalize this thought. Suppose that you are building a multi-tenant application with a
different database for each tenant. There will be far more than four databases.
You probably don't want to set up different servers for each one. It is easier to have a single
(load-balanced) server address and tell the server at that address which tenant database to use.
User input can provide the client application with the information it needs to determine which
tenant environment to use. Now we have to tell the server about it.
The EntityManager tells the server which data source to use by sending two types of
information in each request:
1. The DataSourceKeyName that identifies the data source schema
2. The DataSourceExtension that identifies which one of the schema-matching databases
to use.
DataSourceKeyName
Every entity model is associated with a data source. The data source is typically a database
and we'll assume it is a database in this discussion. The schema of that database maps to the
entity classes in the model. You could say that the schemas of the entity model and the
database are matched.
However, the entity model doesn't know which concrete database holds the actual data for the
application. Your application code shouldn't know either. The actual database to use at
runtime is determined by a connection string; that's a configuration concern best relegated
outside the client code base.
A distributed client application (e.g., a Silverlight application) should never contain database
connections strings of any kind. The connection string is never needed on the client and it's a
serious security violation to have one there.
Instead a DevForce application refers to the database by name, by its DataSourceKeyName
resolution logic on the server determines which connection string to use based on the
DataSourceKeyName associated with the entity classes in the request.
For example, the DataSourceKeyName could be "NorthwindEntities" as it often is in our
sample code. We know that's the key because we typed that name when we created the entity
model. We can also tell by inspecting the attributes on the generated EntityManager and entity
class files:
C#
IbEm.DataSourceKeyName(@"NorthwindEntities")]
public partial class NorthwindEntities : IbEm.EntityManager {}

[IbEm.DataSourceKeyName(@"NorthwindEntities")]
public partial class Customer : IbEm.Entity {}
VB
<IbEm.DataSourceKeyName("NorthwindEntities")>
Partial Public Class NorthwindEntities
Inherits IbEm.EntityManager
End Class

<IbEm.DataSourceKeyName("NorthwindEntities")>
Partial Public Class Customer
Inherits IbEm.Entity
End Class
DataSourceExtension
The DataSourceKeyName identified the database schema to use - some kind of Northwind
database - but it didn't tell us which concrete database to use. It doesn't tell us which of many
possible versions of the Northwind database to use.
That's the job of the DataSourceExtension. The DataSourceExtension is a string that
DevForce combines with the DataSourceKeyName to determine the concrete database to use.
The "NorthwindEntities" DataSourceKeyName tells the server that the client wants some
version of a Northwind database; the value of the DataSourceExtension tells the server which
specific Northwind database.
The DataSourceExtension string value is up to you. You devise your own extension naming
scheme. It might be "Dev", "Test", "Stage" and "Prod". It could be the Tenant ID.
The trick is in what you do with that string
Construct an EntityManager with a DataSourceExtension
The client application, having acquired the appropriate DataSourceExtension string value for
the logged-in user, passes that DataSourceExtension into the constructor of a new
EntityManager.
Here is the declaration for the most frequently used EntityManager constructor:
C#
public EntityManager(
bool shouldConnect=true,
string dataSourceExtension=null, // data source environment to use
IbEm.EntityServiceOption
entityServiceOption=IbEm.EntityServiceOption.UseDefaultService,
string compositionContextName=null);
VB
Public Sub New( _
Optional ByVal shouldConnect As Boolean =True, _
Optional ByVal dataSourceExtension As String =Nothing, _
Optional ByVal entityServiceOption As IbEm.EntityServiceOption
=IbEm.EntityServiceOption.UseDefaultService, _
Optional ByVal compositionContextName As String =Nothing)
End Sub
Our focus in this topic is on the dataSourceExtension parameter which is null by default. That
means the EntityManager expects to query and save data to the default data source. The server
should know which database is the default database.
If the client wanted to target a particular database, say the "Test" database, it could do so with
code such as this:
C# manager = new NorthwindEntities(dataSourceExtension: "Test" );
VB manager = New NorthwindEntities(dataSourceExtension: "Test" )
Henceforth, this manager is dedicated to the "Test" environment and will always tell the
server to query and save to the "Test" version of the database.
Please be advised that currently the '+' sign is a reserved character that must not be used in a
DataSourceExtension string. If you do, you will receive the following error:
IdeaBlade.Core.IdeaBladeException: Unable to find a compositionContext with the
name: ..... Other than this, any character is safe as long as it's valid for a file name.
The server interprets the DataSourceExtension
What the server actually does with the DataSourceExtension is beyond the scope of this
topic.
In brief, DevForce server components combine the DataSourceExtension from the
EntityManager with the DataSourceKeyName inscribed in the entity types mentioned in the
request.
Remember that query and save requests involve entities and each entity is adorned with an
attribute identifying its DataSourceKeyName - the kind of database it maps to.
That combination of strings is handed to a DataSourceResolver - one you can replace - that
identifies the appropriate database and its connection string. The entityserver is then equipped
to process the request.
Many models per manager
The EntityManager can pool entities from many models with multiple data sources. The
EntityManager is not limited to the entities of one model or one database. A single
EntityManager instance can
contain POCO entities and regular DevForce entities from multiple models
simultaneously.
query entities from different models.
save changed entities to different data sources in a single transaction; DevForce uses a
distributed transaction if the data sources support it.
By default, when DevForce generates the base code for a model, it also code generates a
custom EntityManager that contains pre-defined queries for entities in that model (e.g.
entityManager.Customers where entityManager = new NorthwindIBEntities()).
However, these pre-defined queries are just for syntactic convenience, and in fact, any
EntityManager can query for entities from any model. Instead of using the pre-defined
property for the query, you just call GetQuery with the entity type that you want:
C#
manager = new EntityManager(); // Creates an "untyped" EntityManager
// - but you can use any EntityManager
var query = manager.GetQuery<Customer>(); // "Get all customers" query
query.ExecuteAsync();
// listen for completed event and do something
VB
manager = new EntityManager() ' Creates an "untyped" EntityManager
' - but you can use any EntityManager
dim query = manager.GetQuery<Customer>() ' "Get all customers" query
query.ExecuteAsync()
' listen for completed event and do something
The entity types are tied to a particular data source by its DataSourceKey name. The
EntityManager and EntityServer learn from the entities they see which data sources are
involved in a requested operation.
That model-specificity of entities is apparent in their generated class code; notice the
DataSourceKeyName attribute adorning the Customer class:
C#
IbEm.DataSourceKeyName(@"NorthwindEntities")]
public partial class Customer : IbEm.Entity {}
VB
<IbEm.DataSourceKeyName("NorthwindEntities")>
Partial Public Class Customer Inherits IbEm.Entity
End Class
DevForce generates a strongly-typed subclass of the EntityManager such as
NorthwindIBEntities that appears to be tied to a single model because it has supplemental
properties and methods that are specific to one model. Managers are typically used with one
model and these extra member make it convenient to work with that model. But, like every
EntityManager, the derived manager can contain entities from multiple models, query from
multiple models, and save to multiple databases.
DevForce code generation does add a DataSourceKeyName attribute to the derived
EntityManager. The attribute is notional and in no way restricts that EntityManager's ability
to work simultaneously with entities from multiple models.
























Multiple EntityManagers
Create multiple EntityManagers when you need to isolate one set of entities (and their
changes) from another set of unmodified entities. The need typically arises when launching an
editor in a "sandbox"; changes within the editor are provisional and confined to the editor
scope.


Some applications only need a single EntityManager instance. That instance can hold in its
cache every entity the application ever needs. The user queries, changes, and saves entities
using that one manager. An ASP application should only require one manager.
However, we often see multiple EntityManagers in smart client and RIA applications. We
tend to cache entities for longer periods - often the entire session - and soon discover that we
need to maintain separate, isolated caches.
Entities are unique within a manager's cache - there can be only one Customer with Id=42 in a
particular cache. If I change the customer's name from "Acme" to "Beta", that change is
visible to every view referencing that customer. That isn't always desirable. We may want two
copies of Customer #42 that we use for different purposes.
Multiple managers help us work with multiple copies of the same entity and they provide
entity isolation because they each have their own caches.
Multi-manager scenarios
Two multi-manager scenarios are common:
1. "Sandbox editor" - when you want to isolate the edited entities from the main set of entities.
You don't want the changes to propagate to the main set until they are saved.
2. "Search manager" - a manager's cache can grow quite large as the user searches for items as
when browing a product catalog. Once specific items are selected, the interim search results
are no longer interesting and they hog memory. It's easy and harmless to throw them away if
they are confined to a search-only manager that you can clear.
Sandbox editor
Customer #42 can appear twice in the same application if it is cached in two separate
managers. Suppose the main manager 'A' supports a customer selection view and manager 'B'
is the isolated manager within the "sandbox editor". Changing the customer's name in the
editor from "Acme" to "Beta" effects the Customer #42 in manager 'B' and is visible only
within the editor. Users looking at the customer selection view will see the Customer #42 in
manager 'A' whose name remains "Acme".
If the user saves the name change in the editor, the stored name of Customer #42 becomes
"Beta". It's still "Acme" back in manager 'A' and in the customer selection view. The situation
for managers 'A' and 'B' is analagous to two separate users who are looking at the same
customers.
If the user should see a refreshed and current view of Customer #42, the developer must take
steps to update that customer in manager 'A', perhaps through a messaging mechanism.
See the blog post "Sandbox" Editors with ClientUI Contacts for an example and discussion.
Take this a step further. Suppose the application can edit multiple customers at the same time.
It might open an editor for Customer #42 and another for Customer #007. Now there are three
managers in play, each with their isolated caches. The user can toggle among them, making
changes to #42, then #007, then back to #42, then canceling the #007 edit session, and finally
saving changes to #42 which propagate back to the main customer selection view.
Multiple managers are handy when you have to juggle ongoing tasks like this.
Search manager
Imagine a shopping application in which manager 'A' holds products to purchase. The user,
while searching for more items to purchase, is busily querying products, perhaps hundreds of
them, most of which will not end up in the shopping cart. The volume could be substantial
and the toll on local memory severe. When the user is ready to checkout, those unwanted
products are dead weight.
You could try to identify and purge them from manager 'A', taking care to separate the
product entities mentioned in the cart from the vast majority of unwanted products.
It might be easier to conduct the search using a manager 'B'. When the user picks an item, you
copy it from 'B' to 'A' (using ImportEntities ). When the shopping is over, you clear manager
'B'.
Create a second EntityManager
Create a second manager the same way you did the first. You have the same range of options.
Consider using the handy copy constructor that creates a new EntityManager configured like
its source.
C# var secondManager = new EntityManager(firstManager);
VB Dim SecondManager = New EntityManager(FirstManager)
One critical consideration: each new EntityManager gets its own security context by
default .. and must be separately logged in by default.
You may not notice this during early development, before you have established your authentication
process. You will discover it if you require an EntityManager to login. The second manager will throw
an exception when you try to use it, complaining that the manager has not been logged in (see
Secure).
Rarely (if ever) do you want to authenticate each manager separately, not even if login is
implicit and seemingly automatic. Fortunately, you don't have to. You can tell the second
manager to get its security context from the first manager using the
LinkForAuthentication method.
C#
var em1 = new EntityManager();
em1.Login(new LoginCredential("demo", "demo", "earth"));
var em2 = new EntityManager();
em2.LinkForAuthentication(em1);
VB
Dim em1 = New EntityManager()
em1.Login(New LoginCredential("demo", "demo", "earth"))
Dim em2 = New EntityManager()
em2.LinkForAuthentication(em1)
The new EntityManager, em2, has the same security contexts as its prototype, em1. It will not
require its own login to fetch or save data.
Don't call LinkForAuthentication if you used the copy constructor described above; it
establishes that linkage automatically.













The entity cache
The entity cache is an in-memory container of entity objects controlled by its
EntityManager . You query entities into the cache. You display and edit entities in cache. You
save changed entities from the cache to the database. This topic tells you what you need to
know about the cache before encountering it again in other topics.


The EntityManager maintains a cache of entities. A query puts retrieved entities in the cache.
You add newly created entities to cache. When you ask the manager to save, it saves the
changed entities that it finds in its cache.
Most of the time you work with entities that reside in a manager's entity cache. You can work
with entities that are not yet in cache and entities that were once in cache but have since been
detached. But that's unusual. Many of the important features of entities, including the ability
to navigate to related entities and to save changes, are only available when the entities reside
in cache.
Entities in cache are unique
An entity is identified by its EntityKey, an object consisting of a type (e.g., Customer) and the
values of its key properties (e.g., the value returned by the CustomerID property).
All entities in cache have unique EntityKeys; a cache can't have two instances of Customer
with the same CustomerID. Of course no one can prevent you from creating two Customer
objects with the same CustomerID. But they can't both be in the same EntityManager cache at
the same time.
This is true for deleted entities as well. They may seem invisible but they are there, in cache,
until they are saved. Only after they have been saved successfully do they depart the cache.
Add entities to cache
Entities usually enter the cache as a by-product of a query. DevForce always puts queried
entities in cache.
You add entities to cache explictly in three ways:
1. By adding it to a manager with the AddEntity method. An added entity is regarded as
a new entity that will be inserted into the database if saved.
2. By attaching it to a manager with the AttachEntity method. An attached entity is
regarded as an existing, unmodified entity like one that has been queried.
3. By importing it with the manager's ImportEntities method.
Remove entities from cache
Deleting an existing entity doesn't remove it from cache but saving a deleted entity does. The
save removes the deleted entity implicitly. You can remove an entity from cache explicitly as
well:
C# manager.RemoveEntity(someCustomer);
VB manager.RemoveEntity(someCustomer)
Call the manager's Clear method to remove every entity from the cache.
Is the entity in cache or not?
In the code above, someCustomer is a reference to a Customer entity. They entity didn't
disappear because we removed it from cache. It's still an entity. It's now a Detached entity.
We can ask the entity if it is in cache or Detached by inquiring about its entitystate. The
following line verifies that someCustomer was detached after we removed it.
C# Assert.IsTrue(someCustomer.EntityAspect.EntityState.IsDetached());
VB Assert.IsTrue(someCustomer.EntityAspect.EntityState.IsDetached())
EntityState can tell us more than whether the entity is attached or detached.

Find entities in cache
You can query the cache for entities and confine that query to the cache with a CacheOnly
QueryStrategy .
But there's a more direct way to find entities in the cache: use one of the FindEntities methods
such as this one that finds an entity by its EntityKey:
C#
var foundCust = manager.FindEntity(cust1.EntityAspect.EntityKey);
Assert.AreSame(cust1, foundCust);
VB
Dim foundCust = manager.FindEntity(cust1.EntityAspect.EntityKey)
Assert.AreSame(cust1, foundCust)
Unlike a query, you can find an entity in cache even if it is deleted.
C#
cust1.EntityAspect.Delete(); // marked for deletion
var foundCust =
manager.FindEntity(cust1.EntityAspect.EntityKey, includeDeleted:true );
Assert.AreSame(cust1, foundCust);
VB
cust1.EntityAspect.Delete() ' marked for deletion
Dim foundCust =
manager.FindEntity(cust1.EntityAspect.EntityKey, includeDeleted:=True )
Assert.AreSame(cust1, foundCust)
You can also find entities in cache using LINQ for objects:
C#
var foundCust = manager
.FindEntities(EntityState.AllButDetached)
.OfType<Customer>()
.Where(c => c.CompanyName == "Acme") // cust1's name
.FirstOrDefault();

Assert.AreSame(cust1, foundCust);
VB
Dim foundCust = manager _
.FindEntities(EntityState.AllButDetached) _
.OfType(Of Customer)() _
.Where(Function(c) c.CompanyName = "Acme") _
.FirstOrDefault()

Assert.AreSame(cust1, foundCust)
Notice that
FindEntities filters by entitystate; here we ask for all cached states (AllButDetached).
FindEntities returns an IEnumerable; we cast it to IEnumerable of Customer in order
to query it with LINQ.
Export cache as an EntityCacheState
The EntityManager itself is not serializable. But its cache contents are serializable when in the
form of an EntityCacheState . An EntityCacheState is a snapshot of the entities in cache. This
snapshot can be handed around inside the client application, serialized to file, restored from
file, even sent to the server as a parameter in a remote server method call.
To get an EntityCacheState, start with the manager's CacheStateManager . Its GetCacheState
method can return an EntityCacheState with all or only some of the entities in cache.
In the following unrealistic example, we use an EntityCacheState to copy a cache from one
manager to another:
C#
// Get EntityCacheState with all cached entities using the CacheStateManager
var ecs = manager1.CacheStateManager.GetCacheState();

// Create 2nd manager
var manager2 = new EntityManager(shouldConnect: false);

// "Restore" into manager2 with the contents of the ECS from manager1
manager2.CacheStateManager.RestoreCacheState(ecs);

// Prove that manager2 has a customer with same ID as cust1
var foundCust = manager2.FindEntity(cust1.EntityAspect.EntityKey);

// But the foundCust is not the same as cust1
// because cust1 still belongs to manager1
Assert.AreNotSame(cust1, foundCust);
VB
' Get EntityCacheState with all cached entities using the CacheStateManager
Dim ecs = manager1.CacheStateManager.GetCacheState()

' Create 2nd manager
Dim manager2 = New EntityManager(shouldConnect:= False)

' "Restore" into manager2 with the contents of the ECS from manager1
manager2.CacheStateManager.RestoreCacheState(ecs)

' Prove that manager2 has a customer with same ID as cust1
Dim foundCust = manager2.FindEntity(cust1.EntityAspect.EntityKey)

' But the foundCust is not the same as cust1
' because cust1 still belongs to manager1
Assert.AreNotSame(cust1, foundCust)
A CacheStateManager can also save or restore an EntityCacheState from a file.
Entity cache structure
You rarely need to probe around inside the entity cache itself. The cache-only query and the
Find methods are the preferred ways to retrieve entities from cache.
When you need to watch the cache for activity regarding a particular type, it helps to know
about EntityGroups . The cache is organized a collection of EntityGroups. Each group holds
the cached entities for a particular type of entity.
You can discover what entity types the manager has seen by asking for its EntityGroups
C#
manager = new EntityManager(shouldConnect:false);
Assert.AreEqual(0, manager.GetEntityGroups().Count());
VB
manager = New EntityManager(shouldConnect:=False)
Assert.AreEqual(0, manager.GetEntityGroups().Count())
A new manager's cache has no groups. It acquires groups as different entity types are added to
the cache or are referred to by an entity that was queried into cache.
C#
manager = new EntityManager(shouldConnect:false);
manager.AddEntity(new Customer());
Assert.AreEqual(1, manager.GetEntityGroups().Count());
VB
manager = New EntityManager(shouldConnect:=False)
manager.AddEntity(New Customer())
Assert.AreEqual(1, manager.GetEntityGroups().Count())
You can ask for a specific EntityGroup:
C# customerGroup = manager.GetEntityGroup<Customer>();
VB customerGroup = manager.GetEntityGroup(Of Customer)()
Clearing the manager's cache (manager.Clear()) removes all groups.
Listen to cache changes
The cache can tell you when an entity has been attached, changed, or detached.
The following fragment shows how to listen for any change to the cache or to cache changes
for a particular entity type.
C#
// Listen for all changes to cache
var cacheChanges = new List<EntityAction>();
int cacheChangeCount = 0;
manager.EntityChanged += (s, e) => cacheChanges.Add(e.Action);

// Listen for changes to customers in cache
var custChanges = new List<EntityAction>();
int custChangeCount = 0;
var custGrp = manager.GetEntityGroup<Customer>();
custGrp.EntityChanged += (s, e) => custChanges.Add(e.Action);

// Customer changes
var cust = new Customer();
manager.AddEntity(cust); cacheChangeCount++; custChangeCount++;
cust.CompanyName = "Acme"; cacheChangeCount++; custChangeCount++;
cust.CompanyName = "Beta"; cacheChangeCount++; custChangeCount++;
cust.EntityAspect.AcceptChanges(); cacheChangeCount++; custChangeCount++;
cust.EntityAspect.Delete(); cacheChangeCount++; custChangeCount++;

// Employee change
var emp = new Employee {EmployeeID = 42};
manager.AttachEntity(emp); cacheChangeCount++;

Assert.AreEqual(cacheChangeCount, cacheChanges.Count(),
"not all cache changes were signaled");

Assert.AreEqual(custChangeCount, custChanges.Count(),
"not all cust changes were signaled");

Assert.IsTrue(cacheChangeCount > custChangeCount,
"should have more cache changes than cust changes");
VB
' Listen for all changes to cache
Dim cacheChanges = New List(Of EntityAction)()
Dim cacheChangeCount As Integer = 0
AddHandler manager.EntityChanged, Sub(s, e) cacheChanges.Add(e.Action)

' Listen for changes to customers in cache
Dim custChanges = New List(Of EntityAction)()
Dim custChangeCount As Integer = 0
Dim custGrp = manager.GetEntityGroup(Of Customer)()
AddHandler custGrp.EntityChanged, Sub(s, e) custChanges.Add(e.Action)

' Customer changes
Dim cust = New Customer()
manager.AddEntity(cust)
cacheChangeCount += 1
custChangeCount += 1

cust.CompanyName = "Acme"
cacheChangeCount += 1
custChangeCount += 1

cust.CompanyName = "Beta"
cacheChangeCount += 1
custChangeCount += 1

cust.EntityAspect.AcceptChanges()
cacheChangeCount += 1
custChangeCount += 1

cust.EntityAspect.Delete()
cacheChangeCount += 1
custChangeCount += 1

' Employee change
Dim emp = New Employee With {.EmployeeID = 42}
manager.AttachEntity(emp)
cacheChangeCount += 1

Assert.AreEqual(cacheChangeCount, cacheChanges.Count(), "not all cache changes were
signaled")

Assert.AreEqual(custChangeCount, custChanges.Count(), "not all cust changes were
signaled")







Program asynchronously
All client / server communications in Silverlight must be asynchronous and desktop
applications probably should be. Asynchronous programming requires some care and
techniques that may be unfamiliar. This topic describes the asynchronous operations in
DevForce and how to use them.


The DevForce EntityManager in the full .NET library sports numerous methods for
communicating from the client to the server, split 50/50 between synchronous and
asynchronous versions.
DevForce synchronous operations
When using the synchronous versions, the client code makes a call and waits for the server to
return.
C#
results = manager.ExecuteQuery(someQuery);
doSomething(results); // called after server returns
VB
results = manager.ExecuteQuery(someQuery)()
doSomething(results) ' called after server returns
The application on the calling thread blocks until the server returns its reply. If it takes awhile,
the calling code waits. If the calling code is UI code, the user will be staring at a frozen screen
until the queried entities arrive.
It could be a long wait. The asynchronous operations might be a better choice. They don't
deliver server results any faster. They do let you keep the UI alive. The user might be able to
do other work while waiting. Even if they can't, the application can show that it is still
running and perhaps tell the user how matters are progressing.
DevForce asynchronous operations
Many synchronous methods aren't even available in the Silverlight EntityManager, since
Silverlight disallows synchronous communications with the server. Only queries which may
be fulfilled from cache can be executed synchronously in Silverlight. All service methods are
asynchronous; they include:
ConnectAsync
LoginAsync
LogoutAsync
ExecuteQueryAsync
ExecuteQueryAsync<T>
SaveChangesAsync
RefetchEntitiesAsync
InvokeServerMethodAsync
You have to take a different approach when using these methods. The synchronous code we
wrote earlier doesn't translate literally to an asynchronous alternative. For example, this won't
do what you're expecting:
C#
// Not what you are expecting
results = manager.ExecuteQueryAsync(someQuery);
doSomething(results); // called immediately, before results arrive
VB
' Not what you are expecting
results = manager.ExecuteQueryAsync(someQuery)()
doSomething(results) ' called immediately, before results arrive
Two critical observations:
The results variable is not an entity collection. Asynchronous methods don't return
results. They return an operation coordinator object, as we'll see.
That "operation coordinator" object will contain queried entities at some point in the
future. But query results won't be available when doSomething(results) is called.
More precisely, they won't be available if query processing includes a trip to the server. If the
query can be satisfied entirely from cache, the results are returned immediately and the
operation appears to be synchronous. We ignore that possibility for now as this discussion
concerns operations that talk to the server.
It is in the nature of any asynchronous method call that control flows immediately to the next
line and you cannot predict when the server will return with results. If you care when the
results arrive, you must provide some means for the asynchronous operation to notify you.
DevForce asynchronous methods can notify you in one of two ways:
1. by invoking your callback method
2. by raising a Completed event
C#
// with callback
manager.ExecuteQueryAsync(query1, queryCompletedCallback);
// with CompletedEvent
operation = manager.ExecuteQueryAsync(query2);
operation.Completed += queryCompletedHandler;
VB
' with callback
manager.ExecuteQueryAsync(query1, queryCompletedCallback)
' with CompletedEvent
operation = manager.ExecuteQueryAsync(query2)
AddHandler operation.Completed, AddressOf queryCompletedHandler
All DevForce asynchronous methods support these two approaches.
Anatomy of an asynchronous method
The ExecuteQueryAsync signature tells a more complete story:
C#
public EntityQueryOperation<T> ExecuteQueryAsync<T>(
IEntityQuery<T> query,
Action<EntityQueryOperation<T>> userCallback = null,
Object userState = null)
VB
Public Function ExecuteQueryAsync(Of T)(
ByVal query As IEntityQuery(Of T), _
ByVal Optional userCallback As Action(Of EntityQueryOperation(Of T)) = Nothing, _
ByVal Optional userState As Object = Nothing _
As EntityQueryOperation(Of T)
Let's break this signature down starting with the method's returned value and proceeding
through the parameters.
All asynchronous methods return an "operation coordinator" object ending in the word
"Operation". In this example, it is an EntityQueryOperation with a type parameter 'T'
specifying the type of the query result. 'T' would be Customer if the query returned Customer
entities.
The other asynchronous methods have their own operation object types such as the
EntitySaveOperation for a save. They all derive from the DevForce BaseOperation class and
therefore share many of the same behaviors and members such as a Completed event.
The operation object is not the operation itself. It is an object that represents the operation in
progress. You can ask it questions such as "are you finished?" and "do you have errors?". You
can tell it to cancel the operation. It is a vehicle for coordinating the caller and the operation.
Most developers just call it "operation" for the sake of brevity.
Most asynchronous methods take a functional parameter such as the query. This is the same
parameter that would be passed into the corresponding synchronous method.

Next is the optional callback method. The callback is an Action that takes the operation
coordination object as its sole parameter. This is the same object that was returned by the
method, the EntityQueryOperation<T> object in our example.
The last parameter is an optional userState. The userState is an arbitrary object of your
choosing. You supply a userState when you need to pass some information to the callback
method or Completed event handler. You might use it to distinguish one query from another.
The userState object can be as simple as an integer or it can be an arbitrarily complex custom
type. DevForce assigns a Guid if you don't specify a value.
The userState object need not be serializable because it never leaves the client; the server
never sees it.
Callback methods
An asynchronous operation callback method takes an operation coordination object parameter
as seen in this example.
C# void AllCustomersQuery() {
var query = new EntityQuery<Customer>();
manager.ExecuteQueryAsync(query, CustomerQueryCallback);
}

void CustomerQueryCallback(EntityQueryOperation<Customer> op) {
if (op.CompletedSuccessfully) {
var resultList = op.Results;
Console.WriteLine("Query returned {0} entities", resultList.Count());
} else { /* do something with op.Error */ }
}
VB
Sub AllCustomersQuery()
Dim query = New EntityQuery(Of Customer)
manager.ExecuteQueryAsync(query, AddressOf CustomerQueryCallback)
End Sub

Sub CustomerQueryCallback(ByVal op As EntityQueryOperation(Of Customer))
If (op.CompletedSuccessfully) Then
Dim resultList = op.Results
Console.WriteLine("Query returned {0} entities", resultList.Count())
Else
' do something with op.Error
End If
End Sub
Catching errors and handling them properly is always important, especially for
communications with a server. The server or network may go down at any time, so all server
calls should have error handling to ensure your application doesn't crash. You can't wrap your
asynchronous calls in a try/catch; you must handle errors explicitly via the operation object, a
subject covered below.
Do not call the Results property unless the operation has completed successfully. It is a
mistake to ask for results when they are undefined. DevForce can't simply return null because
null is a potentially valid query result. DevForce throws an exception instead.
Many developers prefer to use a lambda callback for economy of expression:
C#
void AllCustomersQuery() {
var query = new EntityQuery<Customer>();
manager.ExecuteQueryAsync(query, op => {
if (op.CompletedSuccessfully) {
var resultList = op.Results;
Console.WriteLine("Query returned {0} entities", resultList.Count());
} else { /* do something with op.Error */ }
});
}
VB
Sub AllCustomersQuery()
Dim query = New EntityQuery(Of Customer)
manager.ExecuteQueryAsync(query, Sub(op)
If (op.CompletedSuccessfully) Then
Dim resultList = op.Results
Console.WriteLine("Query returned {0} entities", resultList.Count())
Else
' do something with op.Error
End If
End Sub)
End Sub
Completed event handlers
Instead of a callback you may prefer to listen to the Completed event. In the next code sample,
we simplify the query and call its ExecuteAsync method instead of the EntityManager's
ExecuteQueryAsync. The principles and practices are the same as before.
C#
void AllCustomersQuery() {
var op = manager.Customers.ExecuteAsync();
op.Completed += CustomerQueryCompletedHandler;
}

void CustomerQueryCompletedHandler(
object sender, EntityQueriedEventArgs<Customer> args) {
if (args.CompletedSuccessfully) {
var resultList = args.Results;
Console.WriteLine("Query returned {0} entities", resultList.Count());
} else { /* do something with args.Error */ }
}
VB
Sub AllCustomersQuery()
Dim op = manager.Customers.ExecuteAsync()
AddHandler op.Completed, AddressOf CustomerQueryCompletedHandler
End Sub

Sub CustomerQueryCompletedHandler( _
ByVal sender as Object, ByVal args As EntityQueryOperation(Of Customer))
If (args .CompletedSuccessfully) Then
Dim resultList = args .Results
Console.WriteLine("Query returned {0} entities", resultList.Count())
Else
' do something with args .Error
End If
End Sub
The handler takes an EventArgs instead of an operation coordination object but the effect is
the same.
You can use a lambda expression here too:
C#
void AllCustomersQuery() {
var op = manager.Customers.ExecuteAsync();
op.Completed += (o, args) => {
if (args.CompletedSuccessfully) {
var resultList = args.Results;
Console.WriteLine("Query returned {0} entities", resultList.Count());
} else { /* do something with args.Error */ }
};
}
VB
Sub AllCustomersQuery()
Dim op = Manager.Customers.ExecuteAsync()
AddHandler op.Completed,
Sub(o As Object, args As EntityQueriedEventArgs(Of Customer))
If args.CompletedSuccessfully Then
Dim resultList = args.Results
Console.WriteLine("Query returned {0} entities", resultList.Count())
Else ' do something with args.Error
End If
End Sub
End Sub
The operation coordination object
The operation coordination object and the EventArgs have additional members. These differ
depending upon the operation performed; consult the API documentation for details.
BaseOperation reveals the members in common.
Member Description
CanCancel Get if this operation is cancellable.
Cancel() Try to cancel the operation. It may (still) be cancellable.
Cancelled Get if the operation was canceled before it completed.
Completed
Raised when the operation has completed, successfully or
otherwise. A synonym for IsCompleted.
CompletedSuccessfully
Get if the operation completed without error and without having
been cancelled.
CompletedSynchronously
Get if the operation was actually processed synchronously entirely
on the caller's thread without a trip to the server. This happens
frequently with query operations that are completely satisfied by
cached entities.
Error
If the operation failed, this property returns the error as an
Exception. Returns null if there is no error (yet).
HasError Get if the operation failed with an error.
IsCompleted
Get if the operation finished, successfully or otherwise. A
synonym for Completed.
IsErrorHandled
Get or set whether the error was handled. Error handling logic
must set this to true; you usually call the MarkErrorAsHandled
method. If the operation failed and this property is not true,
DevForce re-throws the error, an exception that you cannot catch
is likely to terminate the application. See error handling for details.
MarkErrorAsHandled() Sets the IsErrorHandled property to true.
PropertyChanged Raised when one of the operation's public properties has changed.
UserState
Get the custom object that carries information from the caller to
the callback.
Error handling
We mentioned above that you can't wrap your asynchronous method in a try/catch. But you
must still be on the lookout for errors, since any unhandled exception from an asynchronous
operation will terminate the application.
The exception raised by the asynchronous operation is returned in the Error property of the
operation or EventArgs object. These expose the following properties useful in error
detection and handling:
CompletedSuccessfully - true if the operation completed without error and was not
canceled
HasError - true if there was an error
Error - the exception, if there was an error
IsErrorHandled- true if the error has been handled
MarkErrorAsHandled- called to indicate the error has been handled and should not be
rethrown
It's your responsibility to inspect the operation object when the async operation completes and
address failures.
Mark the error "as handled"
If an async operation completes with an error and you don't either call MarkErrorAsHandled
or set IsErrorHandled to true, then DevForce will re-throw the exception. You won't be able
to catch this re-thrown exception, and your application will crash.
If you don't want the unhandled exception to terminate your application, you must:
1. Detect the exception by examining the async operation HasError property.
2. Process the exception as you see fit. The only viable option may be to log the
exception or display a user-friendly error message. If a communication failure has
occurred you can switch your application to offline mode. How you handle the error is
up to you.
3. If the application should continue then mark the error as handled. Remember that
users don't generally appreciate an application which crashes with obscure error
messages.
Here's our query completed handler from earlier with a bit more error handling:
C#
void CustomerQueryCompletedHandler(object sender,
EntityQueriedEventArgs<Customer> args)
if (args.CompletedSuccessfully) {
var resultList = args.Results;
Console.WriteLine("Query returned {0} entities", resultList.Count());
} else if (args.HasError) {
HandleError(args.Error); // Your choice - log the error, show a message, ...
args.MarkErrorAsHandled();
}
}
VB
Sub CustomerQueryCompletedHandler( _
ByVal sender as Object, ByVal args As EntityQueryOperation(Of Customer))
If args.CompletedSuccessfully Then
Dim resultList = args.Results
Console.WriteLine("Query returned {0} entities", resultList.Count())
ElseIf args.HasError Then
HandleError(args.Error) ' Your choice - log the error, show a message, ...
args.MarkErrorAsHandled()
End If
End Sub
IAsyncResult asynchronous pattern
The EntityManager also supports the IAsyncResult asynchronous pattern through an explicit
implementation of the IEntityManagerAsync interface . You will need to cast an
EntityManager to this interface in order to use methods that follow this pattern.
In the IAsyncResult pattern, an asynchronous operation named "SomeOperation" is
implemented as two methods named BeginSomeOperation and EndSomeOperation














Batch asynchronous tasks with coroutines
This topic describes how to batch multiple asynchronous tasks with coroutines. "Batching"
means executing asynchronous operations as a group and waiting for the group to finish.


You can batch asynchronous tasks in parallel or serially.
In a parallel batch, all tasks are launched at once; the caller is notified when they all finish or
one of them fails. Use the DevForce Parallel Coroutine to create and manage a parallel batch.
In a serial batch, the asynchronous operations are executed in order. The first operation must
complete before the second operation can start; the third operation has to wait for the second
operation to complete; so it goes until the last of the operations delivers the final result. Use
the DevForce Serial Coroutine to manage a serial batch.
Microsoft announced forthcoming C# and VB support for asynchronous programming - the
"async/Async" and "await/Await" keywords - at PDC 2010. We expect this approach to
obviate the need for Coroutines, perhaps parallel as well as serial. Meanwhile, you'll
appreciate our Coroutine class and the style it fosters which is much like the "await"-style.
Serial asynchronous batching background
In the absence of coroutines, the obvious approach to sequencing a batch of asynchronous
tasks is to build a chain of callbacks. You arrange for the first operation's callback to start the
second operation ... whose callback starts the third operation ... until your final operation
delivers the result in its callback.
It works but the code is difficult to read and maintain. There are callbacks inside of callbacks
inside of callbacks. They look like deeply nested "if ... else" statements. It's usually worse
when you insert logic at every step to account for errors that might be thrown if one of the
operations fails.
The "Serial async challenge" topic explores the problem and this particular scenario in greater
depth.
Coroutines are a cleaner way to approach this problem. With Coroutines, we can write down a
sequence of asynchronous tasks as if they were going to execute synchronously. They will
actually run asynchronously but they will appear to be a series of synchronous calls, each of
them blocking until it is finished ... as we'll see.
Jeremy Likness wrote a nice blog post on the problem which he describes as follows:
We have asynchronous calls that we want to process sequentially without having to chain
dozens of methods or resort to complex lambda expressions. How do we do it?
He goes on to explain Coroutines and how they address this problem. Finally, he points to
several available Coroutine implementations.
We looked at those implementations. We didn't love with any of them. Either they were too
complicated or too closely coupled with particular UI technologies. Caliburn's "IResult", for
example, depends upon an ActionExecutionContext with eight members, two of
which are WPF/Silverlight specific (FrameworkElement, DependencyObject). That
makes sense if you confine your use of Coroutines to the XAML UI client technologies. We
wanted to support asynchronous programming in non-UI contexts and we wanted to rely on
interfaces that were as small as possible.
The DevForce Coroutine Class
DevForce version 6.0.6 introduces the Coroutine class. We think you'll prefer our
implementation for most - if not all - of your asynchronous programming needs.
The Coroutine class resides in EntityModel for this release. It actually has no dependency on
Entities; it lives here temporarily and will relocate to IdeaBlade.Core in a future release.
Don't worry ... your code won't break. We'll use "type forwarding" so your original references
will continue to work.
Let's start with a simple example.
Imagine that user must make calls to some "top customers". The sales manager prepared a list
of "top customers" for each sales rep to call first thing in the morning. When the sales rep
launches the application, the list of top customers should be on screen.
Due to an unfortunate design decision, each "top customers" list has CustomerIDs but no
relationship to Customers. You won't be able to get the customer information in a single
query. You'll have to get the sales rep's "top customers" first, fish out the CustomerIDs, and
use them in a second query to get the full Customer entities and the information to present on
screen. That's two queries and the second one can't start until the first one finishes.
You'll want to encapsulate the sequence in a single asynchronous method. Here is that
method:
C#
// Coroutine caller
private void LoadTopCustomers() {

var coop = Coroutine.Start(LoadTopCustomersCoroutine);
coop.Completed += (sender, args) => {

if (args.CompletedSuccessfully) {
ShowTopCustomers(coop.Result as IList<Customer>);
} else {
HandleError(args);
}

}
}
Clearly LoadTopCustomers involves an asynchronous operation. You cannot completely
escape the asynchronous nature of the process.
On the bright side, there is exactly one asynchronous operation, the result of the static
Coroutine.Start method. That method takes a companion coroutine that we wrote to
handle the sequence of queries necessary to deliver the top customers. We'll get to that
coroutine in a moment.
Before we do, we note that when the coroutine completes ...
if it completed successfully, we take its Result, cast it as a list of Customers, and
give that to the ShowTopCustomers method which knows how to put those
customers on screen.
if the coroutine failed, we let the host's HandleError method figure out how to
present the failure to the user.
Move on to the coroutine, LoadTopCustomerCoroutine. This is the heart of the
Coroutine business.
C#
// Coroutine Iterator
private IEnumerable<INotifyCompleted> LoadTopCustomersCoroutine() {

var userId = CurrentUser.UserId;

var topCustOperation = Manager.Customers
.Where(tc => tc.SalesRepID == userId)
.Select(tc.CustomerIDs); // project just the CustomerIDs
.ExecuteAsync());

yield return topCustOperation; // SUSPEND

IList<Guid> salesRepsTopCustIDs = topCustOperation.Results;

var salesRepCustsOperation = Manager.Customers
.Where(c => salesRepsTopCustIDs .Contains(c.CustomerID))
.ExecuteAsync();

yield return salesRepCustsOperation; // SUSPEND

// DONE... with list of Customer entities in Coroutine result
yield return Coroutine.Return(salesRepCustsOperation.Results);

}
Visual Basic developers can not code in this iterator style because VB.NET does not support
iterators or the yield statement. Call the Coroutine with a function list instead; this approach
uses iterators under the hood while shielding the developer from the yield statements. This
alternative technique is also useful in many C# scenarios.
Concentrate on the body of the method. There are only seven statements:
1. Get the sales rep's User ID from a static so we can select the top customers for this
particular rep
2. Issue an async projection query for this sales rep's top customers. The "Select" clause
tells you its a projection that will return a list of Customer IDs
3. Yield the query operation object from the ExecuteAsync() call.
4. Pour the query results (the Customer IDs) into a list variable,
salesRepsTopCustIDs
5. Issue a second async query, one that returns every customer whose ID is in the
salesRepsTopCustIDs list.
6. Yield the query operation object from the ExecuteAsync() call.
7. Yield (for the last time) the results of the sales rep's customer query.
Reads like a normal procedure, don't you agree? Except for the yield return keywords.
The linear flow, from top to bottom, is what we're after. If you had to add another
asynchronous operation somewhere in the mix ... you'd have no trouble doing so. You'd
simply follow the pattern you see here:
write synchronously until you come to an asynchronous method.
yield return the operation object result of each asynchronous DevForce method.
at the very end, write: "yield return
Coroutine.Return(the_final_result);"
Passing Context into the Coroutine
The co-routine iterator seems fully self-sufficient in our example. Look closer. Notice that it
requires a userId to filter "top customers" and it needs an EntityManager. The
userId comes from the static "CurrentUser" class and it gets an
EntityManager from a convenient, ambient "Manager" property.
What if you are not so fortunate? What if you think passing parameters via statics is (ahem)
not the right architecture for you? You want the caller to provide "context" to the iterator from
the outside, freeing the iterator from unnecessary dependencies.
Let's rewrite the skeleton of our example to show how we might do that:
C#
// Coroutine Iterator
private IEnumerable<INotifyCompleted>
LoadTopCustomersCoroutine(ModelEntityManager manager, int userId) { // A

var topCustOperation = manager.Customers
.Where(tc => tc.SalesRepID == userId)
.Select(tc.CustomerIDs); // project just the CustomerIDs
.ExecuteAsync());

yield return topCustOperation; // SUSPEND

// ... SAME AS BEFORE ...

}// Coroutine caller
private void LoadTopCustomers(ModelEntityManager manager, int userId) {

var coop = Coroutine.Start(
() => LoadTopCustomersCoroutine(manager, userId); // B

coop.Completed += ... // SAME AS BEFORE
}
The key is to (A) re-define the coroutine method to accept the context and (B) wrap the
coroutine call in an "Action Lambda" before passing that into the Coroutine.Start().
Here are the two lines of interest.
A)
IEnumerable<INotifyCompleted> LoadTopCustomersCoroutine(ModelE
ntityManager manager, int userId)
B) Coroutine.Start( () => LoadTopCustomersCoroutine(manager,
userId) );
Do not go wild with the parameters. If your iterator seems to need too many context
parameters, the code is telling you to bundle them into a single construct - and a single
concept. Figure out what it is. Make a type to carry that context and build an instance of it
before you even get to the LoadTopCustomers method. Then pass this context object
along the call chain.
How does the DevForce Coroutine work?
Many of you will recognize that this coroutine is a .NET Iterator. Iterators return
IEnumerable<T> and consist of a sequence of statements punctuated by "yield
return" statements ... just as we see here.
For an introduction to the serial async task problem, iterators, and how DevForce Coroutines
work, see The Serial Async Challenge topic. The Serial Coroutine Flow Diagram topic offers
a visual rendition of the DevForce Coroutine behavior.
Good-bye, AsyncSerialTask and AsyncParallelTask
The DevForce AsyncSerialTask class was an earlier attempt to address these asynchronous
batching problems. It has been deprecated in favor of the much easier Coroutine class.
The same goes for the AsyncParallelTask which handled a related scenario. With
AsyncParallelTask you could run several asynchronous tasks simultaneously and wait
for a signal indicating that they had all finished. This capability is now subsumed by the
Coroutine class; see its StartParallel method.
We intend to remove both the AsyncSerialTask and the AsyncParallelTask
classes from DevForce in the first half of 2011; both classes will be available in source code
should you wish to continue using them ... and maintain them yourself.
Serial async challenge
This topic describes the difficulty of writing a sequence of asynchronous operations, each of
which must wait for the prior operation to complete. Coroutines are the recommended
remedy.


What's the big deal?
In "desktop" .NET (console, Windows Forms, ASP, WPF applications) you have the option of
writing a sequence of instructions that include calls to the server. The instruction following a
server call waits - is "blocked" - until the server returns. Consider this schematic example.
C#
public void GetCustomerOrders() {

var custs = new List<Customer>();
GetCustomers(custs); // First server call for customers

var someCusts = SelectCustomersOfInterest(custs); // Local filtering

var orders = new List<Order>();

GetOrdersOfSelectedCustomers(someCusts, orders); // Second server call for orders

var someOrders = FilterCustomerOrders(orders); // local filtering

CustomerOrders = someOrders; // set a property for display
}
The SelectCustomersOfInterest method waits until GetCustomers() returns,
having populated the "custs" list with the queried customers. Then it runs and produces the
subset, someCusts. Then the GetOrdersOfSelectedCustomers method runs while
FilterCustomerOrders waits. When the orders arrive, it filters them and sets the
CustomerOrders property with the filtered orders.
It may seem a bit contrived but this kind of thing happens frequently in user applications. You
want to get some data from the server, process it a little, get some more data, process that a
little, and then display the results on screen.
You can't write code like this in Silverlight. Every trip to the server must be asynchronous
in Silverlight. If you try write methods such as these, you soon discover that
GetCustomers returns immediately with an empty list of
customers. SelectCustomersOfInterest runs immediately - who know what it does
with an empty customer argument. GetOrdersOfSelectedCustomers runs and
instantly returns nothing. FilterCustomerOrders returns nothing. The screen shows
nothing.
Some time later, the server comes back with the initial batch of queried customers but, by that
time, the GetCustomerOrders method has delivered an empty result and your user is
confused. The retrieved customers are never processed. You don't get the selected orders. It's
a disaster.
That's why you've been learning about the DevForce asynchronous operations for querying,
saving, and invoking server methods. You've learned, for example, that you could write the
GetCustomers method something like this:
C#
private EntityQueryOperation<Customer> GetCustomers(List<Customer> customerList) {

// query for all customers
var queryOperation = Manager.Customers.ExecuteAsync();

// upon success, pour the customers into the supplied customer list
queryOperation.Completed += (s,args) => {
if (args.HasError) { HandleTrouble(args); }
customerList.AddRange(args.Results);
};

// return the query operation so caller can wait
return queryOperation;
}
Plug that back into the original example and GetCustomerOrders starts to look like:
C#
public void GetCustomerOrders() {

var custs = new List<Customer>();
var custOperation = GetCustomers(custs); // Get customers into list

List<Customer> someCusts;
var custOperation.Completed += (s, args) => {
someCusts = SelectCustomersOfInterest(custs);
};

// we're not done yet

}
The good news is that SelectCustomersOfInterest won't start filtering the "custs"
list until it actually has some customers in it. Although GetCustomerOrders still returns
immediately - you can't escape the fundamental asynchronous nature of the process - at least
you've got this part of the sequence behaving properly.
The bad news is you've written a lot of tricky code and you are only half way home. You still
have to get the orders for "someCustomers" - wait - and filter them before displaying
them.
Imagine we've written a GetOrdersOfSelectedCustomers in the same fashion as
GetCustomers
C#
private EntityQueryOperation<Order> GetOrdersOfSelectedCustomers(
List<Customer> customerList, List<Order> orderList) {

// get the ids of the selected customers
var ids = customerList.Select(c => c.CustomerID).ToList();

// query for orders of customers who have ids in the selected id list
var queryOperation = Manager.Orders
.Where(o => o.ids.Contains(o.CustomerID))
.ExecuteAsync();

// upon success, pour those orders into the supplied orderList
queryOperation.Completed += (s,args) => {
if (args.HasError) { HandleTrouble(args); }
customerList.AddRange(args.Results);
};

// return the query operation so caller can wait
return queryOperation;
}
Let's rewrite GetCustomerOrders to use it:
C#
public void GetCustomerOrders() {

var custs = new List<Customer>();
var custOperation = GetCustomers(custs); // Get customers into list

var custOperation.Completed += (s, args) => {

var someCusts = SelectCustomersOfInterest(custs);
var orders = new List<Order>();
var orderOperation = GetOrdersOfSelectedCustomers(someCusts, orders);

orderOperation += (s, args) => {

var someOrders = FilterCustomerOrders(orders);
CustomerOrders = someOrders; // set property for display
}
};

}
We've got logic distributed over several helper methods and two levels of indentation in our
master method. Notice the "Staircase Effect" and imagine if we had to introduce yet another
asynchronous operation.
When is it done?
How does the caller of GetCustomerOrders know when all operations have completed
successfully? In other words, how does the caller know when the
CustomerOrders property has been set?
Answer: it can't know. Our GetCustomerOrders method has no mechanism for telling
the caller when all operations are complete.
Could you change the signature to return something that the caller could use? Think about
what that would be. Could you return the first operation object (custOperation)?
You could but it wouldn't solve the problem. The caller could listen for when the customer
query completed. But that is only the first step in the sequence. The caller wants to know
when the last operation completes.
Could you change the signature to return "orderOperation" which is the last operation
object?
No ... you cannot. The "orderOperation" object isn't defined until after you've retrieved
customers. GetCustomers must return something immediately; there is no way to stall
until we've defined the orderOperation object.
What if one of the operations throws an exception?
The GetCustomers and GetOrdersOfSelectedCustomers methods intercept
errors via a "HandleTrouble" method. Where did that method come from? Probably from
the caller. How did it get into our helper methods? Looks like our query methods are tightly
coupled to the caller. That's not going to work long term. To maintain these methods properly
and even consider reusing them, we have to disentangle them from the class that happens to
be calling them right now.
Face it. The query methods shouldn't know what to do about errors. They shouldn't have
specific knowledge about the caller. We want our async methods to propagate errors back to
the caller (who should know what to do with them) in some general, de-coupled way.
Bring on the Coroutine
We're about to describe the DevForce Coroutine in prose and code. Check out the Serial
Coroutine Flow Diagram topic for a more visual rendition of the same subject.
Here is the same example we considered above, written this time with the DevForce
Coroutine.
C#
// Coroutine Host Method
public CoroutineOperation GetCustomerOrders() {
return Coroutine.Start(CustomerOrdersLoader);
}

//Coroutine Iterator
private IEnumerable<INotifyCompleted> CustomerOrdersLoader() {

var custs = new List<Customer>();

// Query for every customer in the database
var custOperation = Manager.Customers.ExecuteAsync();

yield return custOperation; // SUSPEND

custs.AddRange(custOperation.Results);

// Reduce to an "interesting" subset of all customer by
// filtering in some undisclosed fashion
var someCusts = SelectCustomersOfInterest(custs);

// Extract the ids of the selected customers
var ids = someCusts.Select(c => c.CustomerID).ToList();

// Query for any order with a customer whose id is in that id list
var orderOperation = = Manager.Orders
.Where(o => ids.Contains(o.CustomerID))
.ExecuteAsync();

yield return orderOperation; // SUSPEND

var someOrders = FilterCustomerOrders(orders);
CustomerOrders = someOrders; // set property for display

}
First note that the Coroutine.Start method returns a CoroutineOperation object.
This is a derivative of the DevForce BaseOperation class ... just like returned value of
every other DevForce asynchronous method.
Yes ... the Coroutine is itself an asynchronous operation. It is special in that it bundles into a
single package a collection of many asynchronous operations (aka, "tasks"). Life is much
easier for the Coroutine caller which need only wait for a single Coroutine completion event
... rather than cope with the completions of many individual tasks.
We can't see the caller in this example ... the "thing" that calls GetCustomerOrders. But
we should expect this caller to add an event handler to the CoroutineOperation's Completed
event ... a handler that will take care of business when the Coroutine reports "all tasks
completed."
Let's turn our attention to what we can see - the Coroutine.Start and the
CustomerOrdersLoader that is passed to it as a parameter.
The "Co" in "Coroutine" implies at least two cooperating actors. The two actors are (1) the
"Provider" and (2) the "Consumer".
The "Provider" is your code that performs one task after another. Some of the tasks are
synchronous, some of them asynchronous.
CustomerOrderLoader is the Provider in this code sample. As you can see,
CustomerOrderLoader does a little synchronous work (e.g., variable initialization) for
awhile. Then it hits an asynchronous method at which point it "yields" to its partner, the
"Consumer".
What does the Producer yield? It yields the result of the asynchronous method. That result
happens to be a special kind of "Coroutine coordination object" with information about the
asynchronous task currently underway.
A Cooroutine coordination object must implement the DevForce
INotifyCompleted interface. Every DevForce asynchronous method returns an object
that implements INotifyCompleted. Therefore, every DevForce asynchronous method
returns an object that can both participate in Coroutine processing and report the status and
outcome of an async operation.
To whom does the Producer yield? It yields to the DevForce Coroutine class. Actually, it
yields to a hidden DevForce "Consumer" that receives the "coordination object". While you
don't actually see the Consumer ... or interact with it directly... it's there, the invisible partner
to your Producer co-routine.
The Consumer takes the Producer's "coordination object" and immediately injects its own
callback method. This is the method that the "coordination object" will call when the
asynchronous operation completes.
Then the Consumer method let's go.
At this point, both the Consumer and the Producer are suspended. Technically, they aren't
running at all. They are methods which, seemingly, have done their work and finished.
But both the DevForce Consumer and your coroutine Producer are poised to resume work
when the asynchronous operation completes.
When that async operation completes, it raises a Completed event on its operation result
object. We just saw that this "operation result object" is also a Coroutine coordination object.
In that capacity, it also invokes the callback method that the Consumer injected.
That injected callback method effectively revives the Consumer. The Consumer examines the
outcome of the asynchronous operation. If the operation completed successfully, the
Consumer, calls upon the Producer, asking the Producer for the next "coordination object".
The Producer method, instead of starting over, picks up where it left off. In our code sample,
it picks up just after the first "yield return" where it adds the results of the customer
query to the "custs" list.
The Producer continues executing until it comes to the next asynchronous operation, the
query for Orders. Then it yields a second time, returning a different "coordination object" to
the Consumer, the operation object returned by the Orders query.
Again, the Consumer injects its callback into the coordination object and both Consumer and
Producer are suspended again ...
Until the Orders query completes.
And when it completes, the coordination object calls the Consumer, the Consumer sees that
everything is still ok and calls the Producer. The Producer resumes where it left off, filters the
Orders, and sets the caller's CustomerOrders property.
This time there is no more work to do. There are no more asynchronous operations and no
more "yield return" statements. So (implicitly) the Producer tells the Consumer, "I'm
done."
The Consumer, realizing that there are no more tasks, wraps up and raises the Completed
event on its CoroutineOperation object.
Do you remember that object? That was the object returned by GetCustomerOrders. As
we noted above, the GetCustomerOrders caller added its own handler to the
CoroutineOperation. That handler kicks in and does whatever needs doing now that all
of the asynchronous tasks in the Producer co-routine have finished.
An Iterator Tutorial
The co-routine dance works well because we write the task logic in a linear fashion, much as
we write a fully synchronous procedural method.
Visual Basic developers can not code in this iterator style because VB.NET does not support iterators
or the yield statement. Call the Coroutine with a function list instead; this approach uses iterators
under the hood while shielding the developer from the yield statements. This alternative technique is
also useful in many C# scenarios.
The kicker is that "yield return" statement which suspends the Producer while the
asynchronous operation works in background. The "yield return" syntax is the tell-tale
sign of an "Iterator".
The iterator is the key to the async coroutine pattern. You've undoubtedly used an iterator but
you may not have known it and may never have written one.
Iterators are not a DevForce invention. They've been around in the literature for a long time.
Iterators were added to .NET in version 2.0. They're a mechanism for generating values on
demand. Here's an example:
C#
public IEnumerable IntegerIterator(int start, int end){
for (int i = start; i <= end; i++) {
yield return i;
}
}
You usually consume it with a foreach expression like so:
C#
foreach (int n in this.IntegerIterator(1, 10)){
System.Console.Write(n + " ");
}
// Output: 1 2 3 4 5 6 7 8 9 10
A C# foreach takes something that produces an IEnumerable and "iterates over it" ,
by which we mean, it repeatedly asks the IEnumerable for a next value until the
IEnumerable has no more values to give. The IEnumerable could be a collection of
values. Or, as in this case, it could be a producer of values.
Iterators can produce values in all kinds of ways. Here's one way that is similar to what you've
seen in a coroutine:
C#
public IEnumerable StringIterator(){
yield return "My dog";
yield return "has";
yield return "fleas";
}
We can consume it with a foreach just as we did the IntegerGenerator:
C#
foreach (int str in this.StringIterator()){
System.Console.WriteLine(str);
}
// Output: My dog
// has
// fleas
The foreach calls our StringIterator three times because there are three yields. The
StringIterator "remembers" where it last yielded. The first call yields "My dog" ... and
StringIterator positions itself so that the next time it is called, it yields "has". And the next
time it yields "fleas". And the next time it reports "I've got nothing else to give you".
The iterator is suspended after each yield. By "suspended" I mean that the iterator stops. I do
not mean that the thread is suspended or that the iterator is "waiting". The iterator is "done" in
much the way that any other method you call is done when it hits a return statement.
But there is a crucial difference. Any other method would start from its beginning. When you
call the iterator, it resumes where it left off. The iterator maintains a snapshot if its current
state and a bookmark of the execution step where it yielded. When called again, it goes to that
bookmark, revives the saved state, and continues from there.
Mixing regular and yielding statements
The iterator may be composed with a combination of regular and "yield return"
statements. We can rewrite the previous iterator as follows; it produces exactly the same
output.
C#
public IEnumerable StringIterator(){

var myDog = "My dog";
yield return myDog;

var has = "has";
yield return has;

var ignored = "you'll never see this";
var pulgas = "fleas";
yield return pulgas;
}
After each call, the iterator evaluates the next series of statement until it encounters a "yield
return". This iterator returns three strings as it did before but this time, each string takes
two or three statements to product.
The ability to interleave regular and yielding statement is critical to the asynchronous
Coroutine pattern. In real world applications, our iterators need to mix synchronous
statements with asynchronous statements that yield until the async operation returns.
Quitting an iterator early
Your iterator logic may require you to terminate an iterator early, ignoring the remaining
statements. The pertinent syntax is "yield break" as shown here:
C#
public IEnumerable StringIterator(){

yield return "My dog";
yield return "has";

yield break; // Ignore everything below this point

yield return "fleas"; // never executed
}

// Output: My dog
// has















Serial coroutine flow
This topic diagrams the flow of control for a serial coroutine call.
The actors in the diagram are:




Caller: your code that calls the Coroutine.Start method and monitors the
CoroutineOperation object (shown in the diagram as "Coroutine Result")
Producer: your code that provides the sequence of synchronous and asynchronous statements
you want executed as a single unit of work. It's the primary argument your caller provides to
the Coroutine.Start method. If you write ,Coroutine.Start(LoadCustomerInfoCoroutine), then
LoadCustomerInfoCoroutine is your Producer.
The Producer is usually implemented as a .NET Iterator. After each asynchronous operation,
your iterator yields a DevForce INotifyCompleted object such as the OperationBase-
derivative returned by a DevForce asynchronous operation. For example, if the asynchronous
task were a query such as Manager.Customers.ExecuteAsync(); your iterator would yield
return the EntityQueryOperation<Customer> object returned by that query method.
Consumer: A DevForce Coroutine "Consumer" co-routine works with the "Producer" to
move forward through the sequence of asynchronous serial tasks. The Consumer and
Producer are partners: the "Consumer" manages the flow, the "Producer" provides the tasks.
You won't actually see the Consumer coroutine ... it's a hidden by-product of the DevForce
Coroutine.Start(producer) call. But it's helpful to know that something is there, working with
your Producer to make the magic happen.
You will see numbered balls in the diagram. These are the INotifyCompleted objects (aka,
"Coordinator" objects) that are passed around among the Caller, Consumer and Producer.
The asynchronous operations themselves are also represented by the numbered balls; when
they complete, they make changes to the Coordinator objects such as setting the results, error
flags, cancellation flags ... and most importantly, they both raise the Completed event and
invoke the Consumer callback function that tells the Consumer to take the next evaluation
step.


A Serial Coroutine Story in Pictures
The Caller asks the Coroutine to start. It hands back a CoroutineOperation object (aka
"Coordinator") containing information about task processing and, ultimately, the disposition
of the asynchronous operations - the tasks - encapsulated by the Coroutine "Producer".
The CoroutineOperation object has a Completed event. The Caller typically adds a handler to
this Completed event; the handler will know what to do when all of the co-routine tasks have
finished.

The DevForce Coroutine class consumes notifications yielded by the "Producer". It
commands the Producer to give it the next notification.
Typically, a Producer is an Iterator function that returns an
IEnumerable<INotifyCompleted>. The consumer extracts from this function an
Enumerator (an implementor of the IEnumerator interface) which offers "MoveNext()"
and "Current" members. These members combine to fulfill the "Get next" command
semantics.

The Producer does some work. It encounters an asynchronous method call. It yields the
OperationBase object returned by the asynchronous method (e.g., an
EntityQueryOperation<Customer> object from a query such as
Manager.Customers.ExecuteAsync()).
OperationBase implements INotifyCompleted and is thus the kind of
"Coordinator" object that the DevForce Coroutine Consumer expects.
Note that the asynchronous operation has not completed yet (it's still gray). The Producer is
done for the moment. It is suspended until the Consumer asks for the next
INotifyCompleted object.

The DevForce Coroutine Consumer adds the received INotifyCompleted object to the
CoroutineOperation.Notifications collection.
The DevForce Coroutine Consumer stops at this point. In effect it suspends further processing
It won't ask the Producer for the next INotifyCompleted object .. until "reawakened" by
a callback from the "Coordinator" object - the INotifyCompleted object just yielded by
the Producer.
The application continues to run. The two co-routines - Producer and Consumer - are poised
to continue to the next task. But neither makes a move until the pending asynchronous
operation completes ... and calls the Producer.

The asynchronous operation finishes at last, raising its Completed event and signaling success
(It's green!). Because the asynchronous operation object implements INotifyCompleted,
it also calls back to the DevForce Coroutine Consumer.
The reawakened Consumer sees that the asynchronous operation returned successfully ...

... so the Consumer asks the Producer for the next INotifyCompleted "Coordination"
object.

The cycle repeats:
The Producer does some work until it encounters another asynchronous function.
It yields that asynchronous function's returned value, an INotifyCompleted object.
The Consumer adds that object to the Notifications list of the
CoroutineOperation object (shown as "Coroutine Result" in the diagram)
The asynchronous operation eventually succeeds, raises its Completed event and calls the
Consumer to tell it about that success.

After three more cycles the Producer indicates that has no more Notifications to yield (the
MoveNext() method returns false).

The DevForce Coroutine Consumer raises its own Completed event.
The Caller has been listening for this event and now knows that the Coroutine has completed
all of its tasks successfully.
More precisely, the handler that the Caller attached to the CoroutineOperation's Completed
event is ready to interpret the outcome of the co-routine tasks.
The handler can inspect the CoroutineOperation object's Notifications collection and
examine any of the asynchronous tasks that were completed.
Usually it only cares about the last one. The handler will often extract results from the last
completed operation or perhaps from the CoroutineOperation object itself.
It's really up to the handler what happens next; the co-routines have done their jobs.

Failure
Perhaps something went wrong with the second asynchronous operation. It raises its
Completed event but its EventArgs indicate an error. The asynchronous operation calls
back to the DevForce Coroutine Consumer - just as it would if the operation had succeeded.

The DevForce Coroutine Consumer sees the error. It observes that the error was not handled*
so it concludes that it should stop asking the Producer for more notifications. It won't call the
Producer's MoveNext() method again. Instead, it raises the Completed event of the
CoroutineOperation object ("Coroutine Result" in the diagram).
The Caller's handler is listening to that event. The Caller's handler sees that there was a failure
and must decide what to do next.
If the Caller's handler neglects to call "MarkAsHandled()" on the CoroutineOperation object,
the DevForce Coroutine will throw the exception.

* The"Producer" could have attached its own Completed handler to the asynchronous
operation object. The Producer's Completed handler gets the first look ... before the Coroutine
sees the Completed event. If the Producer's handler marks the asynchronous operation object
as handled (e.g., by calling MarkAsHandled()), then the Coroutine Consumer will resume the
process and ask the Producer for the next Notification object.
Events versus Callbacks
We've told this story as if Completed events and event handlers were "the way to go". Most
developers prefer events. But the Coroutine and asynchronous methods all support callback
delegates. You are welcome to use callbacks instead of the Completed events.









Parallel async coroutines
Use a parallel asynchronous coroutine when two or more asynchronous tasks should run
simultaneously and you want to be notified when all of them have completed ... or if any one
of them fails.


We've focused on batching Asynchronous Serial Tasks because it's a common pain point that
cries out for some relief.
Having slain that dragon, you discover another one in the same cave. You have several
asynchronous tasks that must finish collectively but they are mutually independent and you
don't care which finishes first. You suspect that your application might run faster if you fired
them off together and let the caller work on something else until all of the parallel tasks are
done.
You suspect ... but you do not know. The watch word for performance tuning is "measure.".
Measure before and after. Measure for different runtime environments. We have seen plenty
of multi-threaded code that ran slower than the original single-threaded approach. While it is
often the case that a batch of IO tasks, such as fetching entities from a remote database,
complete significantly faster when run in parallel, we urge you to test that assumption in your
application.
A parallel scenario: loading lists at launch
Many applications rely on lots of small lists: lists of states or provinces, lists of status codes,
lists of suppliers, etc. Most are very stable (the provinces) and might be worth enshrining in
the code. However, you have your good reasons to read them in from the database when the
application launches.
Your application will not function properly until all of the lists are loaded. You don't care are
about load order; you just want to hold back the user until they've all arrived.
You noticed that waiting for the server to deliver these lists one by one is painfully slow. The
size of each list is not the issue - they are all tiny. It's the number of server trips that is killing
responsiveness. Most of the overhead is in managing the conversation with the server, not in
database query or in the transmission of data. Your client is idle while you wait for each list
result. Maybe you can speed things up by firing off a bunch of requests at once. You could be
right about that.
You're first thought is to pull down everything you need in a single query. Sometimes you can
do that .. .see "Retrieving Many Types in a Single Query" below. More often you can't. There
is probably no relationship - neither inheritance nor navigational - among the entities you
want to retrieve. You have to issue separate queries for each list.
Coroutine.StartParallel()
The DevForce Coroutine class is a good solution to this problem. It operates much like serial
asynchronous batching except you'll call Coroutine.StartParallel (coroutine) instead of
Coroutine.Start (coroutine).
Two kinds of Coroutine are quite similar. An individual serial asynchronous task looks like an
individual parallel asynchronous task. A batch of asynchronous serial tasks looks much like a
batch of asynchronous parallel tasks. A producer of asynchronous tasks (such a the coroutine
iterator) yields the same kind of INotifyCompleted objects.
The critical difference - and it is critical - is that parallel tasks cannot not share their data with
each other. They must be completely independent of each other - you can't use the result of
one as the input to another - and you should not care whether one finishes before the other.
This difference aside, batches of asynchronous serial and parallel tasks are structurally the
same.
In DevForce you define a batch of tasks the same way: with a co-routine that returns an
IEnumerable<INotifyCompleted>. Here's an example:
C#
// Coroutine parallel task iterator
private IEnumerable<INotifyCompleted> LoadListEntitiesCoroutine() {

yield return Manager.Employees.ExecuteAsync(); // only 7 in Northwind
yield return Manager.Regions.ExecuteAsync()();
yield return Manager.Territories.ExecuteAsync()();
yield return Manager.Suppliers.ExecuteAsync()();

// not in Northwind but you get the idea
yield return Manager.StatesProvinces.ExecuteAsync()();
yield return Manager.Colors.ExecuteAsync()();

}
Each line launches an asynchronous query and yields the query's coordinating "Operation"
object result.
Once you've defined a batch of tasks, you need some collaborating component to run them for
you, to decide when the batch is done, and to redirect failures to your error handling code.
We've been calling this the DevForce Coroutine "Consumer".
We know what happens if we run this co-routine iterator with the
Serial Coroutine Consumer by calling
Coroutine.Start(LoadListEntitiesCoroutine): the first query runs, wait,
return, then the next one runs, wait, return, and so forth.
That's not what we want. We want "start the first, and the second, and the third ... and the
fifth; now wait until they finish; then tell me about it."
And that's what you get when you call
Coroutine.StartParallel(LoadListEntitiesCoroutine). The DevForce
Parallel Coroutine Consumer immediately walks through the entire iterator launching all
of the asynchronous tasks at once. The iterator yields INotifyCompleted objects (just as
we did in the serial Coroutine example). With each yield, the Parallel Consumer
identifies an individual asynchronous task to watch. It builds a list of these yielded values as
they arrive (see the Notifications collection below).
Happy side-effects of a parallel coroutine
We may not care about the result of our parallel tasks. We might be content with their side-
effects. In this example, we're filling the cache with entities that we'll use later. That may be
all we need to do.
Imagine that we subsequently query for Orders. We want to know which "employee" was the
sales rep who sold that order. The statement anOrder.Employee will find the related employee
available in cache. You won't have to worry about making an asynchronous trip to the server
to get the employee ... because it is waiting for you in cache.
This approach is popular ... for good reason. It's difficult to write a stable, responsive UI that
could fly off to the server any minute for missing data. Development is much easier if you can
set up with everything you need - pay the asynchronous management price up front - and then
operate locally for as long as possible.
If you adopt this approach, it is a good idea to disable the "lazy load" feature by setting the
EntityManager's DefaultQueryStrategy to CacheOnly.
Manager.DefaultQueryStrategy = QueryStrategy.CacheOnly;
You can still query the database for specific information at any time. Just remember to
specify the "go to server" QueryStrategy when you need to make that trip. For example, when
we want to get fresh information about a particular customer, we could write:
C#
Manager.Customers
.Where(c => c.CustomerID == someID)
.With(QueryStrategy.DatabaseThenCache) // go to database first, then check with the
cache
.ExecuteAsync(yourCallback);

// Do other stuff
The phrase that matter is:
.With(QueryStrategy.DatabaseThenCache)
Results of a parallel coroutine
On the other hand, you might want to do something with the parallel task results as soon after
they are all arrive.
A good place to do that is in your parallel task caller ... more precisely, in a callback method
or Completed event handler that you established in your parallel task caller.
C#
// Coroutine caller
private void LoadListEntities() {

var coop = Coroutine.StartParallel(LoadListEntitiesCoroutine);

coop.Completed += (sender, args) => {
if (args.CompletedSuccessfully) {
FillLists(args.Notifications);
} else {
HandleError(args);
}
}
}

private void FillLists(IList<INotifyCompleted> notifications) {

// Although order of finish is indeterminate,
// the order of notifications matches the Coroutine yield order
// Simplistic approach for demo purposes.

EmployeeList = MakeList<Employee>(notifications[0]);
RegionList = MakeList<Region>(notifications[1]);
TerritoryList = MakeList<Territory>(notifications[2]);
SupplierList = MakeList<Supplier>(notifications[3]);
StatesProvinceList = MakeList<StateProvince>(notifications[4]);
ColorList = MakeList<Color>(notifications[5]);
}

private IList<T> MakeList<T>(INotifyCompleted completedArg) {
var op = completedArg as EntityQueryOperation<T> ;
return (null == op) ? new List<T>() : new List<T>(op.Results);
}
The Notifications collection
The highlight of the code example is the Notifications collection. The
Notifications collection is the vehicle for processing task results.
The DevForce Coroutine Consumer adds each value yielded by your co-routine Producer
(your iterator) to this collection in the order received. You access
the Notifications collection from either the CoroutineOperation and
CoroutineCompletedEventArgs.
Such tracking of yielded INotifyCompleted values works for the Serial Asynchronous
Coroutine as well. Only the timing differs. In the serial case, the yielded values appear in
the Notifications collection over time. They'll all get there eventually if the serial
Coroutine succeeds. In the parallel case, they are available immediately.
Retrieving Many Types in a Single Query
Parallel queries are ideal when you have to make a lot of small queries simultaneously. But
each query is its own trip to the server, even when you parallelize them. If you restructured
your database a little bit, you might be able to reduce many of these trips to a single trip.
We're making a digression into "Polymorphic Queries". The intent is the same - to retrieve a
variety of entities at the same time. That's why we're discussing it here. But the technique has
nothing to do with parallel queries.
Maybe you could combine certain kinds of entity types into a single physical table. Then you
could define a common base entity class for that table, model the specific entity classes as
sub-types of the base entity class, and issue a single DevForce "polymorphic query" defined
for the base entity. This will pull down all of the derived entities at once.
We've seen this approach used to good effect with Code entities. Codes often share the same
structure: {Id, CodeName, Description}. You can often store hundreds of different codes in a
single Code table {Id, CodeType, CodeName, Description} and discriminate among them by
the "CodeType" field. You define an abstract base type, "Code", and use Entity Framework
Table-per-Hierarchy (TPH) to model the hundred distinct code entity types as derivatives of
the Code entity.
Start your DevForce application, query for all "Codes", ... and all of the distinct code-like
entities arrive in cache in a single query.
This can be extremely effective ... if you're comfortable with it. Not everyone is; some folks
want the database foreign key constraint to prevent accidentally setting the Order with a Color
code instead of a Shipping code. You have to decide if this is a significant risk for your
application.









Asynchronous errors
This topic discusses asynchronous operation error handling. The specific context is
coroutine errors but the analysis and discussion apply to all DevForce asynchronous
methods.


Errors can arise anywhere in the process. It's not easy to manage exceptions thrown by
asynchronous operations. The Coroutine is asynchronous as are many of its tasks. Silverlight
is an asynchronous world. You have to develop effective exception handling practices to
survive in that world.
Your synchronous programming instincts lead you in the wrong direction. Your first thought
is to wrap the Coroutine.Start() call in a try ... catch like so:
C#
// Coroutine caller
private void LoadTopCustomers() {

CoroutineOperation coop;

// Don't do this!
try {
coop = Coroutine.Start(LoadTopCustomersCoroutine);
catch (Exception ex) {
HandleError(ex);
};

// more code
}
That won't work. Remember that the LoadTopCustomers method completes almost
immediately. It finishes long before the first asynchronous Customer query returns. If the
query fails - perhaps because the connection to the server is broken - the server exception
arrives much later, packaged inside the query operation object (e.g., the
EntityQueryOperation<Customer> object).
You cannot predict when the query will returns. What you do know - for certain - is that if
you don't detect and handle the exception reported by the query, DevForce will re-throw the
exception on the client. You won't be able to trap that exception because you have no clue
where it will be thrown. In practice, it will bubble up to your application's "unhandled
application exception" logic (in App.xaml.cs by default) where your only viable option is
to log the error and terminate the application. Not good.
You can prepare for possible error in either of these two ways:
C#
private void LoadTopCustomers_with_Completed_event_handler() {

CoroutineOperation coop = Coroutine.Start(LoadTopCustomersCoroutine);

coop.Completed += (sender, args) =>
{if (args.HasError) HandleError(args);};

// more code
}

private void LoadTopCustomers_with_callback() {

CoroutineOperation coop =
Coroutine.Start(
LoadTopCustomersCoroutine, // coroutine iterator
op => {if (op.HasError) HandleError(op);} // callback
);

// more code
}
This puts you on the right road. It may not be quite enough; you better call
MarkErrorAsHandled, for example.
But maybe you are already doing that in the HandleError method, in which case you are in
good shape. If you are not sure, read on.
DevForce Async Error Interception
DevForce offers a helpful variety of error handling facilities in the Coroutineclass and in the
other DevForce asynchronous methods. In all cases, exceptions detected within an
asynchronous operation are captured in the async method's "Operation" object - the async
operation coordination object returned by an ExecuteAsync() for example.
All async methods return an async operation coordination object that inherits from
BaseOperation . All BaseOperation classes and their associated asynchronous operation
EventArgs expose the following properties:
CompletedSuccessfully - true if the operation completed without error and was not canceled
HasError - true if there was an error
Error - the exception, if there was an error
Cancelled- true if the operation was canceled.
It's your responsibility to inspect the BaseOperation or EventArgs when the async
operation completes and address failures ... as we did in the original version of
LoadTopCustomerCoroutine.
Your first opportunity to catch an asynchronous operation error is inside your iterator
coroutine.
C#
// Coroutine Iterator
private IEnumerable<INotifyCompleted> LoadTopCustomersCoroutine() {

var userId = CurrentUser.UserId;

var allCustOperation = Manager.Customers.ExecuteAsync(
// Callback checks for error
op => { if (op.HasError) HandleError(op); }
);

// another way to catch errors
var allCustOperation.Completed += (s1, args1) => {
if (args1.HasError) HandleError(args1);
};

yield return allCustOperation; // SUSPEND

// more code

}
Note that we added a callback method to the query's ExecuteAsync - a callback that
checks for the error and calls an appropriate method. We also demonstrated an alternative,
"event handler" approach that does exactly the same thing. Then we yield.
The DevForce Coroutine Consumer receives the yielded operation object and adds its
own handler to the allCustOperation's Completed event.
When the query operation returns, the coroutine callback gets the first crack at interpreting the
results. Then the coroutine Completed event handler gets the next look. The outer
Coroutine Consumer gets the last look.
Note that we arranged to inspect the results before yielding to the DevForce
Coroutine "Consumer". The following example mistakenly adds error interception after
the yield.
(
C#
// Coroutine Iterator
private IEnumerable<INotifyCompleted> LoadTopCustomersCoroutine() {

var userId = CurrentUser.UserId;

var allCustOperation = Manager.Customers.ExecuteAsync();

yield return allCustOperation; // SUSPEND

// Too late. If there was an error, you'll never get here
if (allCustOperation.HasError) HandleError(allCustOperation);

// more code

}
This won't work the way the author intended. The DevForce Coroutine Consumer will
have already inspected the result before giving control back to your coroutine. IF the query
reported an error, DevForce would have discovered that error and (by default) will have
terminated the coroutine immediately. The coroutine error handling code will not run.
Do Not Touch Results Of An Errant Or Canceled Operation
Many async operation coordination objects and their associated EventArgs have a "Result"
or "Results" property. The CoroutineOperation and
CoroutineCompletedEventArgs have a "Result" property.
Such properties are undefined it the operation has an error or was canceled. You will get an
exception if you attempt to access them.
Mark-As-Handled
It's OK to let the query error bubble up to the outer Coroutine. That may be the best place to
handle an error. But that should be a deliberate decision on your part.
You must be aware of the ramifications of that decision ... which means you must know how
the DevForce Coroutine Consumer handles task errors and cancellations.
Most important: you must understand the significance of marking - or failing to mark -
an error "as handled".
There is an IsHandled flag on every async operation object and EventArgs; the flag is not
always visible but it is there. If the async operation completes with an error and you don't set
the IsHandled flag to true somewhere, somehow, then DevForce will re-throw the exception.
You may have examined the exception. You may think you've addressed the exception. But
unless you set IsHandled to true, DevForce has to assume that the exception was unexpected
and re-throw it. Your application is going to crash if DevForce re-throws an async operation
exception because there is no way for you to trap it.
You do not want DevForce to re-throw that error. You want to be in control. And you can
be.
Before we get to how, let's explain why we re-throw it. Note that we cannot tell if you dealt
with the exception or if you missed it. Exceptions indicate trouble. It may be trouble you can
anticipate and recover from ... in which case you should do so ... and tell DevForce that you
did so.
But unhandled exceptions are fatal. The cause does not matter. You should not continue in a
potentially unstable and errant state. The only appropriate course of action is to terminate the
application.
If you don't want DevForce to terminate your application, you must:
1. Detect the exception by examining async operation results
2. Process the exception as you see fit
3. If the application should continue ... you must call MarkErrorAsHandled, a method on every
DevForce async operation and EventArg.
There are several opportunities to call MarkErrorAsHandled ()). This may be best understood
by exploring some scenarios.
Scenario #1: MarkErrorAsHandled not called
1. The DevForce Coroutine Consumer calls your Iterator
2. Your iterator issues an async query
3. Your iterator adds error interception logic (either with a callback or a Completed event
handler)
4. Your iterator yields the query operation coordination object to the Consumer ... and the co-
routines suspend
5. The query fails on the server and returns the server exception
6. DevForce raises the Completed event on the operation coordination object yielded in step
#4. The EventArgs contain the server exception which is also accessible directly from the
operation object itself.
7. Your iterator interception logic, which is either a callback or event handler, examines the
exception
8. The DevForce Coroutine Consumer sees the exception.
9. The DevForce Coroutine Consumer sees that the exception is not marked as handled ... and
terminates the process. It will not ask your iterator for the next yield.
10. The DevForce Coroutine adopts the query exception as its own exception. Now the Coroutine
has an error.
11. You didn't intercept exceptions on the Coroutine either.
12. DevForce concludes that the exception is unhandled and re-throws it.
13. Your application crashes.
Scenario #2: MarkErrorAsHandled called inside the Iterator
5. The query fails on the server and returns the server exception
6. DevForce raises the Completed event on the operation coordination object yielded in step
#4.
7. Your iterator interception logic, which is either a callback or event handler, examines the
exception
8. That interception logic calls MarkErrorAsHandled()
9. The DevForce Coroutine Consumer sees that the exception is handled
10. The DevForce Coroutine resumes calling your coroutine iterator which picks up with the
next step.
Scenario #3: MarkErrorAsHandled called in the Coroutine's operation coordinator
5. The query fails on the server and returns the server exception
6. DevForce raises the Completed event on the operation coordination object yielded in step
#4.
7. By design, you do not have any error interceptor logic in your iterator.
8. The DevForce Coroutine Consumer sees that the exception is not handled ... and
terminates the process. It will not ask your iterator for the next yield.
9. The error bubbles up to the Coroutine operation coordinator (the result of
Coroutine.Start())
10. You have added error interception logic to that operation coordinator object as we
showed at the topic of this topic.
11. That interception logic calls MarkErrorAsHandled()
12. DevForce see that the exception is handled ... and permits your application to continue.
Error in the Coroutine Itself
Your coroutine consists of synchronous and asynchronous statements. Perhaps all of your
async operations succeed ... or would have succeeded. But, sadly, your coroutine threw an
exception.
You probably won't see this exception right away ... not unless it occurs before the first
yield return. Therefore, you can't rely on a try...catch to guard against this kind of
exception either.
Your coroutine is not supposed to throw exceptions but it happens. The outer DevForce
Coroutine Consumer will catch it. You could not have handled that exception inside the
iterator (otherwise, the Coroutine iterator would not have failed) so the Coroutine must
terminate the iterator.
But DevForce will propagate the exception to the Coroutine operation object. Your error
handling at that level can decide what to do. You can MarkErrorAsHandled and permit
the application to continue running if that makes sense.
Parallel Async Coroutine Error Handling
The reasoning and behavior are essentially the same whether you use the Serial Async
Coroutine or the Parallel Async Coroutine.
If you don't handle an exception at some level, DevForce will re-throw it and your application
will most likely crash.
If a coroutine async task results in a handled exception (you called MarkErrorAsHandled,
both Coroutines continue processing the remaining tasks.
The only difference - and it is slight - is how DevForce treats the remaining tasks when your
iterator produces an unhandled error.
The Serial Async Coroutine will stop processing your iterator coroutine the moment it sees a
task with an unhandled exception. It won't run any of the remaining tasks.
In the Parallel case, some or perhaps all of the asynchronous tasks could be running when
the unhandled exception arises. DevForce will try to cancel all outstanding tasks, report them
as canceled, and will ignore their results even if it can't cancel them. Tasks that already
completed will retain their "completed successfully" status and their results remain available.




















Using function lists
This topic describes how to batch multiple asynchronous tasks with coroutines using
function lists. You will likely use this technique when writing coroutines in Visual
Basic.NET.
It's also useful in C# when you want to build up a list of things to do asynchronously rather
than define all those tasks within a single iterator method.


Coroutines in VB.NET
The iterator approach to batching asynchronous tasks is a popular choice in C#.
That choice is not available to Visual Basic.NET programmers because iterators aren't
implemented in VB.NET.
Fortunately, you can still use the DevForce Coroutine class in VB to manage a sequence of
asynchronous tasks. Instead of writing an iterator to produce the sequence, you construct a list
of functions that return INotifyCompleted and pass the list to the Coroutine.
We call this the "function list approach" to coroutines.
The function list approach is also useful in C# when you want to build up a list of things to do
asynchronously rather than define all those tasks within a single iterator method.
Serial coroutine with function list
The basic recipe is as follows
1. Write a "batcher" function that builds a list of asynchronous functions, each returning an
INotifyCompleted object.
2. Call the Coroutine.Start method, passing in the list returned by the batcher.
3. Either include a callback method or attach a handler to the Coroutine.Completed event.
Here is an example that loads all customers, updates them, and saves them back to the
database.
Write the "batcher"
LoadAllCustomersUpdateAndSaveCore is the "batcher" in our example.
C#
private IEnumerable<Func<INotifyCompleted>>
LoadAllCustomersUpdateAndSaveCore(NorthwindEntities manager)
{
// List of asynchronous functions for the Coroutine to execute serially.
var funcList = new List<Func<INotifyCompleted>>();

// Get all customers
funcList.Add(() => manager.Customers.ExecuteAsync());

// Make a change to them and save them
funcList.Add(() =>
{
UpdateAllCachedCustomers(manager); // sync operation to update customers in cache - for
example
return manager.SaveChangesAsync(); // asynchronous operation returning INotifyCompleted
});

// return the list
return funcList;
}
VB
Private Function LoadAllCustomersUpdateAndSaveCore(ByVal manager As NorthwindEntities) _
As IEnumerable(Of Func(Of INotifyCompleted))

' List of asynchronous functions for the Coroutine to execute serially.
Dim funcList = New List(Of Func(Of INotifyCompleted))

' Get all customers
Dim loadFnc As Func(Of INotifyCompleted) =
Function()
Return manager.Customers.ExecuteAsync() ' return an INotifyCompleted
End Function

funcList.Add(loadFnc)

' Make a change to them and save them
Dim saveFnc As Func(Of INotifyCompleted) =
Function()
UpdateAllCachedCustomers(manager) ' sync operation to update customers in cache - for
example
Return manager.SaveChangesAsync() ' return an INotifyCompleted
End Function

funcList.Add(saveFnc)

' return the list
Return funcList
End Function
Observations:
One batcher function fully defines the list of asynchronous tasks to process. Alternatively,
you could build up that list externally and then submit it to the Coroutine class. This example
assumes you want to think about the batch as a single, unified process.
Nesting the asynchronous function definitions within the batcher makes for easier reading as
all steps of the process are in one place.
Each asynchronous function returns a single implementer of INotifyCompleted.
Within that function, all code except the final line must be synchronous. Do not put two
asynchronous methods in the same function. Including synchronous functionality is optional.
The last line of the batcher returns the function list it's built up.
Call Coroutine.Start
The Coroutine.Start method of the DevForce Coroutine class will accept either an iterator or a
list of asynchronous functions. The Coroutine works the same in either case, pausing until
each asynchronous function completes.
C#
var op = Coroutine.Start(LoadAllCustomersUpdateAndSaveCore(manager));
op.Completed += (s, e) => {
if (e.CompletedSuccessfully) {
ShowMessage("All customers were updated");
} else {
ShowMessage(e.Error.Message);
}
};
VB
Dim op = Coroutine.Start(LoadAllCustomersUpdateAndSaveCore(manager))
AddHandler op.Completed, Sub(s As Object, e As CoroutineCompletedEventArgs)
If e.CompletedSuccessfully Then
ShowMessage("All customers were updated")
Else
ShowMessage(e.Error.Message)
End If
End Sub
Parallel coroutine with function list
We can adopt a similar approach to run a collection of asynchronous tasks in parallel.
Imagine a batcher called LoadReferenceEntitiesCore that asynchronously loaded sets of
reference entities such as colors, states, unit types, etc. You would write this in precisely the
same way that you did LoadAllCustomersUpdateAndSaveCore, the only difference would be
in the functions that you added to the funcList.
We'd call StartParallel instead of Start as in this example, which also uses a callback instead
of an event handler.
C#
Coroutine.StartParallel(
LoadAllCustomersUpdateAndSaveCore(manager), // batcher
(op) => // callback
{
if (op.CompletedSuccessfully) {
ShowMessage("References entities loaded");
} else {
ShowMessage(op.Error.Message);
}
}
);
VB
Coroutine.StartParallel( _
LoadReferenceEntitiesCore(manager), _ ' batcher
Sub(op As CoroutineOperation) ' callback
If op.CompletedSuccessfully Then
ShowMessage("Reference entities loaded")
Else
ShowMessage(op.Error.Message)
End If
End Sub













Learn about related technologies
You may find these resources helpful as you work with other technologies in your DevForce
application.
Entity Framework
Programming Entity Framework, 2nd edition, by Julie Lerman. Absolutely essential, for
beginners and experts alike. It's comprehensive and it's big but it's easy to read in small doses.
Get the second edition for Entity Framework version 4 published in August, 2010.
Julie posts about Entity Framework regularly on her blog.
The Microsoft-sponsored videos are short, excellent guides to building entity models in
Visual Studio.
Microsoft maintains a list of resources. The Microsoft documentation on EDM modeling tools
is noteworthy.
C#
C# 4 in a Nutshell by Albahari brothers. By far the best book for the seasoned programmer
and the C# expert who thinks he knows everything. We really like their LINQPad too which
is an incredible interpreter for quickly trying out LINQ and C# expressions.
LINQ
C# 4 in a Nutshell belongs under the C# category but deserves a second mention here for its
crisp and clear treatment of the subject. We think it's the best.
LINQ in Action for gory details
MVVM
Model-View-ViewModel (MVVM) is a recommended pattern for building screens or views.
It is a pattern for arranging UI code.
MVVM is primarily concerned with separating the controls on the glass (the View) from the
logic that feeds and responds to those controls (the ViewModel). The ViewModel often
manages the flow of data between objects in a Model and their presentation in the View
MVVM is not itself a framework nor is there one necessary implementation. In fact, many
DevForce examples and reference implementations are done in MVVM style.
The MVVM pattern and its implementations have almost nothing to say about the Model.
They leave that to you ... or in our case, they leave it to DevForce. DevForce plays well with
all kinds of MVVM implementations. Think of DevForce as supplying the Model to your
MVVM implementation.
Accordingly, you can pick any MVVM style or implementation that works for you... and fit
DevForce right in.
Silverlight
Silverlight 4 Unleashed by Laurent Bugnion (due November 2010). Laurent is the author of
the open source MVVM-Lite Toolkit and the author of the earlier edition for Silverlight 2. A
top choice.
Silverlight 4 in Action by Pete Brown. Excellent content and a pleasure to read. Covers much
the same ground as Laurent's book but with a different perspective. Get both books.
Data Driven Services with Silverlight 2 by John Papa is dated but much of value remains.
Silverlight 4 improves upon but is not radically different than Silverlight 4. The biggest gap
is the absence of WCF RIA Services (which did not exist at the time) and DevForce.
Azure
Azure in Action by Chris Hay and Brian H. Prince. A good choice for learning what Azure is
and why it matters as well as how to make it work.
Windows Identity Foundation
Guide to Claims-Based Identity and Access Control from the Microsoft Patterns and Practices
team. Excellent tour of federated identity issues and how WIF addresses them written with a
minimum of jargon and a maximum of real world sensibility. Why are we even mentioning
WIF? Because more and more of our customers are moving to Azure and the cloud presents
special security challenges for which WIF is well suited. Nuts and bolts books will come ...
but this will endure simply because it is such a clear and compelling introduction to the space.











Create the entity model
Last modified on March 25, 2011 15:39
This topic describes how to create an Entity Data Model (EDM) in Visual Studio using the
EDM Designer that has been supplemented by the DevForce EDM Designer Extension.
These discussions are DevForce focused and often assume a familiarity with Entity
Framework and the tooling that can be learned from other resources.
Start with the EDM Wizard
Create a new Entity Data Model (EDM) with the Entity Framework's EDM Wizard


DevForce developers begin entity model development by defining an Entity Framework
Entity Data Model (EDM). You create a new EDM using the Entity Framework EDM
Wizard.
In this topic we show most of what you need to use the EDM Wizard but it's also worth
looking at Microsoft's
documentation in MSDN
Pick the model project
The first question it "where do I put the model?". You have to pick the project that will be
home to your entity class model.
The DevForce tutorials teach you to begin with a DevForce n-tier template and add the model
to the web application server project. That's a simple way to learn DevForce. Although not
ideal in the long term, don't worry about it now; you can break that model into a separate
project later if you want to.
More experienced DevForce developers create a dedicated model project up front. Make sure
you create the model project as a full .NET 4 class library.
Either way, you'll add your entity model classes to a full .NET 4 project.
Add an ADO Model item
Having decided upon the project that will hold your model, do the following:
Select the project in the Visual Studio 2010 (VS) "Solution Explorer" window
Select "Add a new item" from the context menu (or press Ctrl-Shift-A)
Type "ado" in the search TextBox in the upper right of the dialog
Select the "ADO.NET Entity Data Model" template
Enter a name for the model in the "Name:" box (e.g., DomainModel.edmx)
Press Enter
You have launched the "Entity Data Model Wizard".
Note that the template added the .edmx file extension to your model name; you picked the wrong
template if it didn't.
The wizard offers two ways forward:
1. "Generate from database" - the Data First approach
2. "Empty model" - the Model First approach

Data or Model First?
Do you want to generate the entity model from an existing database? Choose #1 and follow
the "Data First" path. Most developers go this way, either because they are committed to a
legacy database or because they prefer to define the database and the entity model at the same
time.
You might prefer #2 - "Model First" - if you are building the application from scratch, have
no legacy database to worry about, and want to delay defining a database until you've worked
out your entity model.
Both approaches produce a Conceptual Entity Model that defines the shapes and
relationships among the entities that will eventually become your entity classes.
"Data First" produces a full EDM that maps the Conceptual Model to the Storage Model. The
Storage Model describes the database schema; the mapping correlates the Conceptual Entities
with tables and columns in storage. This full EDM is required by the Entity Framework to
read and write to the database.
In this topic we consider only the "Data First" and "Model First" approaches. The Entity Framework
"Code First" does not use an EDMX at all. Try DevForce POCOs if you prefer "Code First".
The "Model First" approach yields an EDMX without mapping and storage descriptions. You
can add the Storage Model and Mapping later but until you do you won't be able to access a
database with this EDM.
DevForce is OK with that. DevForce only needs the Conceptual Model to generate entity
classes. You can develop and test your application quite effectively using an offline entity
cache or a fake backing store populated with dummy data.
When you choose "Empty model", the wizard generates a skeletal EDMX file and sends you
straight to the EDM Designer with a blank canvas. The EDM wizard has done its job. You
proceed to manually add entities and associations to the Conceptual Model.
Create the model from the database
In the "Data First" approach, you point the Wizard at an existing database and tell it to
generate entities corresponding to selected tables and views. This is by far the most common
approach to entity modeling.
Identify the database
First you must identify the database that will be the schema source.
This needn't be the production database; in fact it should not be. Pick a version of the
database with a suitable schema; it should be a database you can read to and write from during
development.
Many developers are comfortable creating and updating a design database using other tools such as
SQL Server Management Studio (SMS). They alternate between the EDM Designer and SMS as they
evolve the model.
The wizard asks you to pick a database connection as in this example:

Your target database will be in the drop-down list if you've previously created a connection to
it in Visual Studio. The "Server Explorer" window reveals the connections known to Visual
Studio at the moment:

You can remove an unwanted connection from the "Server Explorer" - and from the EDM Wizard
connection list - by selecting it and pressing the Delete key.
If the target database is not in the list, press the New Connection... button to open the Visual
Studio "Connection Properties" dialog. This screenshot shows the default connection in SQL
Server for the "NorthwindIB" tutorial database as it was installed with DevForce.

Pick database objects to model
The wizard connects to the database you picked and reads the database schema. This can take
from seconds to minutes. Eventually it presents an "Choose objects" dialog with a list of
database objects categorized by "Tables", "Views", and "Stored Procedures". In the example
shown in the following screenshot, the developer is modeling tables:

Some observations:
1. The "Tables" category shows the database tables that have not yet been modeled. This
developer picked four tables.
2. The wizard can use English language pluralization rules to generate entity class and property
names. When the pluralization option is checked, the wizard creates a Customer entity type
mapped to either a "Customer" (singular) or "Customers" (plural) table. The wizard sees that
a Customer has multiple related orders so it creates a Customer.Orders (plural) navigation
property. The wizard does a decent job of English pluralization; non-English speakers might
turn this off. In any case, you can set these names directly in the designer. You can turn
pluralization on and off later as well.
3. You must check the "Include foreign key columns" option which tells the EDM designer to
create "Foreign Key Associations" and expose foreign key columns as entity properties.
DevForce requires this option.
4. The "Model Namespace" value isn't used by DevForce. DevForce generates the entity classes
with the project's default namespace ... unless you override that default by setting the
"Custom Tool Namespace" property of the DevForce template (the .tt file).
When you press Finish, the wizard generates the EDM and hands off to the EDM Designer.
Now is a good time to save the model and review the EDM's connection to the database.
Refine in the EDM Designer
This topic introduces the Entity Data Model (EDM) Designer which is a Visual Studio tool
for defining conceptual entities and mapping them to the database.


Introduction
The EDM Designer is a Visual Studio design tool for defining your Entity Data Model
(EDM). It reads and updates the EDMX file that represents the model in XML. Every
DevForce developer who is responsible for writing and maintaining an Entity Framework
EDM will use this tool.
You can implement almost every EDM feature with the EDM Designer. A few features
require editing in raw XML and some tasks can be accomplished more quickly in XML. But
the EDM Designer is preferred because the EDMX file is large and challenging to work with
directly.
Microsoft enumerates in its MSDN documentation on the designer those Entity Framework features
that cannot be specified or controlled through the designer.
When you have created a new EDM with the EDM Wizard, the wizard leaves you in the
EDM Designer. If you chose the "Data First" approach and generated the initial model from a
database schema, the EDM Designer might look a bit like this:

The screenshot shows two of the four windows within which you specify the conceptual
entities and how they map to the database.
You may be completely satisfied with the model as it was initialized from the database
schema in which case your next stop might be to review the generated entity classes and start
customizing them with your own business logic.
Most developers adjust the EDM here in the designer in order to shape the entities to meet
their needs. They may want to
change the name of an entity (or property) from its default value which is the name of the
database table (or column).
establish an inheritance hierarchy among some of the entity types.
add a custom base class
designate concurrency properties
specify how keys are generated
consolidate related simple properties into a ComplexType property
add XML documentation that will appear in the generated classes.
The basic workflow for such changes is:
Select the object (entity, property, association) to modify in the diagram or search for it in
the "Model Browser" window.
Set the EDM properties for that object in the "Properties" window.
Adjust mappings in he "Mapping Details" window.
Save, causing DevForce to re-generate the entity classes.
Build the application and test it.
Some of the object properties that you set in the designer are actually DevForce-specific
properties. They were added by the DevForce EDM Designer Extension when you installed
DevForce itself.
Update the model from the database
You probably shouldn't model every table in the database all at once. You'll add new entities
over time and, if you use the Data-First approach, you'll want to initialize those entities and
their mappings from information in the database just as you did when you first created the
model with the EDM Wizard.
When you change the database, you may need to change the EDM to match.
Don't start over. Use the Update Model Wizard described here.
Learn More
The Microsoft documentation in MSDN is a place to start.
Microsoft-sponsored Entity Framework videos are short, excellent guides to building entity
models with the EDM Designer.
Julie Lerman's Programming Entity Framework, 2nd edition is authoritative on Entity
Framework matters in general and the EDM Designer in particular. Julie's blog will keep you
on top of the latest EF techniques.
EDM Designer windows
The Visual Studio EDM Designer has four windows which are introduced in this topic.


You'll define and refine your Entity Data Model (EDM) in the EDM Designer. The designer
uses four windows to display EDM information and take your input as we see in this
screenshot:

The four windows are:
Window Summary
Canvas A design surface that displays a diagram of the conceptual entities.
Model Browser A searchable tree view of EDM objects.
Properties The configuration of the currently selected object.
Mapping Details The correspondence between a conceptual entity and storage objects.
The following sections briefly describe the purpose and capabilities of each window. We
recommend that you consult other resources for more detail; Microsoft's own documentation
on the designer is a good place to start.
Canvas
The "canvas" is a visual design surface for editing the conceptual model. You can create,
modify, or delete entities and associations by interacting with the diagram graphics.

This is the main work area for many developers. Some of the widely used canvas gestures and
actions are discussed in another topic devoted to the subject.
Model Browser
The "Model Browser" is a tree view of the conceptual and storage models.

This is an alternative means of navigating the model and is explored in greater detail here.
Properties Window
The "Properties Window" displays details about entities, entity properties, associations,
complex types, storage objects and the model itself. This snapshot shows the properties of the
Customer's CustomerID key property.

The object properties can be viewed alphabetically or grouped in categories as we see here.
The DevForce EDM Extension added a category of DevForce-specific object properties,
shown here outlined in red.
Learn more about EDM properties, the DevForce properties in particular, in this related topic.
Mapping Details
The Mapping Details window shows how entities and ComplexTypes are mapped to objects
in the storage model.
In this screenshot, the developer selected the Customer entity and opened the Mapping
Details window. It shows how the Customer entity is mapped to the "Customer" table.

The table columns are outlined in red on the left; the corresponding entity properties are
outlined in blue on the right. Although the column and property names are identical in this
mapping, you know the columns are on the left because the data types are database data
types. The property types on the right are entity data types.
The details are editable. This window is used extensively when modeling inheritance
relationships and splitting entities. These somewhat advanced techniques are best learned by
consulting external resources on Entity Framework modeling.
When you select an association and look in the Mapping Details window, it will be empty
as seen here.

If must always be empty because DevForce only supports "Foreign Key" associations.
If an association appears in this window, it is the wrong kind of association and must be fixed.




EDM Designer canvas
The Canvas is the main window in the Visual Studio EDM Designer. It a design surface that
displays a diagram of the conceptual entities that you can navigate and edit. This topic
describes some of what you are likely to do on the canvas.


The "canvas" is a visual design surface for editing the conceptual model. You can create,
modify, or delete entities and associations by interacting with the diagram graphics.

You should consult other resources for more a full understanding of how to work on the
canvas; Microsoft's own documentation on the designer is a good place to start.
In this topic we mention a few of the most useful gestures and actions, starting with the most
important, undo.
Multi-level undo
Mistakes are easy to make, especially as you try unfamiliar features such as deleting entities
and adding ComplexTypes. It's a great comfort to know that the designer supports multi-level
undo (Control-Z) and re-do (Control-Y).
Actions from the bare canvas
Right-mouse-click on any blank spot.

This context menu controls the model as a whole.
Add creates a new entity, association, inheritance, or complex type. You're most likely to use
this feature in Model-First development; The Data-First developer adds and updates entities
via the "Update Model from Database..." option.
Diagram, Zoom, Grid, and Scalar Property Format control the appearance of the diagram.
Model Browser opens the designer's Model Browser window which is the best way to
navigate a large model.
Update Model from Database... is how the Data-First developer adds and updates entities
based on database schema. It launches the Update Model Wizard.
Generate Database from Model.. generates SQL scripts for creation of a database that
matches the current conceptual model. This is useful for the Model-First developer; the Data-
First developer can ignore it.
Properties opens the designer's Properties Window for the model as a whole.
Validate the model
Validate checks the entire model and reports errors and warnings to the Visual Studio "Error
Window". Microsoft documentation lists some of the errors and suggests remedies.
It's worth validating the model regularly while working in the designer, especially after
updating the model from the database.
Errors are usually show-stoppers. You won't be able to generate to use the EDM or generate
clean entity classes until you fix them.
A few you can safely ignore ... when you understand and accept their causes. In Model-First
development you expect to see "Error 11007: Entity type 'SomeEntity' is not mapped" because
you are delaying the mapping exercise until later. It won't prevent code generation.
Entities & associations
This screenshot shows two related entities.

The entity names, Customer and Order, appear in the editable headers at the top of each box.
The line between the entity boxes is the association that relates them. The EDM Wizard
produced that association based on the foreign key relationship between the matching
"Customer" and "Order" tables. The cardinality of the association is denoted in the diagram
by the "0..1 - *" text which means that a Customer has zero or more related Orders.
The Properties section shows both scalar and complex type properties. A scalar property
returns a single value such as a number or a string. Customer.CompanyName is a simple
property returning a string. These two entities only have scalar properties.
A complex type property combines multiple inter-related properties into a single type. Both
Customer and Order might benefit from combining five of their properties into a common
Address complex type.
Navigation Properties appear at the bottom. A navigation property traverses an association
from one entity to another. The Customer.Orders property is a collection navigation
property that returns child orders of a parent customer. The Order.Customer property is a
reference navigation property that returns the parent customer of a child order. Order has
two other navigations to entities not shown.
DevForce implements both reference and collection navigation properties as specialized entity
queries.
You cannot change the display order of the properties in the diagram from within the
designer. The display order is determined by the order of the properties in the EDMX file.
You can edit the EDMX file and re-arrange the XML property definitions in the CSDL
section if the display order matters to you.
Renaming
You can rename an entity or its property in the object on the diagram.

Entity property context menu
Right-mouse-click on a property to get its context menu

Add new properties to the conceptual entity in any of three flavors. You're most likely to use
this feature to add a ComplexType property or when developing inModel-First style. The
Data-First developer adds and updates entities via the "Update Model from Database..."
option.
Refactor into New Complex Type after selecting multiple properties to be combined into a
ComplexType.
Delete removes the property from the entity, leaving the corresponding store column
unmapped. You can re-map that column later. The model validates if the store column
remains unmapped as long as it is nullable or has a store-determined default value. Validate
reports an error otherwise.
Entity Key should be checked if the property participates in the EntityKey; CompanyName
does not.
Table Mapping opens the Mapping Window and displays the mappings for the entity to
which this property belongs - Customer in this case.
Stored Procedure Mapping opens the Mapping Window and displays the stored procedure
mappings for the entity to which this property belongs. DevForce can take advantage of Entity
Framework support for entity stored procedures.
Show in Model Browser opens the Model Browser window and positions focus on the
selected property in the selected entity. The Model Browser is often a more convenient way to
get around in a large model. A similar option in the Model Browser takes you back to the
property in the diagram.
Properties opens the designer's Properties Window for the selected property.
Association context menu
Right-mouse-click on the association line between two entities to see the context menu

Delete removes the association and simultaneously deletes both of its navigation properties.
The model will fail to validate if the storage model mapped that association to a foreign key
relationship in the database.
Select opens a sub-menu with can take you quickly to either end of the association line. It's
enormously helpful when navigating a complex diagram with many long, overlapping
association lines.
Show in Model Browser opens the Model Browser window and positions focus on the
association. The Model Browser is often a more convenient way to get around in a large
model. A similar option in the Model Browser takes you back to this association in the
diagram.
Properties opens the designer's Properties Window for the selected association.
Hover over the association line to reveal the tooltip that indicates (a) the cardinality (0..1 to
many) and (b) the source / target (aka, principal / dependent roles) involved.
Referential Constraint dialog
Double-click an association line to reveal the Referential Constraint dialog

Every association in a DevForce EDM must be a "Foreign Key" association with referential
constraints defined.
Delete entity
To delete an unwanted entity, select it in the canvas, open its context menu and pick Delete.
The "Delete Unmapped Tables and Views Dialog" appears.
The dialog name is misleading. This is the dialog to delete unwanted entities. It can delete the
entity's mapped table (or view) in the process.

The dialog offers three choices which Microsoft seems to have documented incorrectly. The
empirical behavior is as follows:
Yes: Deletes both the selected conceptual model objects and the storage model objects to
which they were mapped. It is on this point that reality and the Microsoft documentation
differ.
No: The selected conceptual model objects will be deleted. "No" means that no storage
model objects will be deleted.
Cancel: The operation is canceled. No objects are deleted .
Yes is the default and is usually what you want. You'd pick No if you wanted to remove the
entity but keep the table. That's rare; you might do this when "splitting an entity" among two
tables as shown in Matthieu Mezil's video.
When you say No, the entities are gone but their tables remains in the Model. Note that EF
doesn't like unmapped tables; the model will fail validation. If you decide not to map the table
after all, use the Model Browser to drop it from the model.
EDM Model Browser

The EDM Designer's Model Browser window presents the conceptual entities and related
database storage objects in a searchable tree view. The Model Browser is an easier way to
navigate a large model than the EDM Designer canvas window.


The Model Browser is one of the EDM Designer windows.
When the EDM gets large, the number of items can overwhelm the EDM Designer canvas.
The diagram becomes small and dense and it is too hard to find the entity or association that
interests you.
The Model Browser affords a more manageable, alphabetically sorted view of the model.
Unlike the canvas, it presents both the conceptual entity model and the related database
storage model in a tree view.
The Model Browser does not display the mappings between the conceptual entities and the storage
schema; for that you go to the EDM Mapping Details window.
Here's a Northwind-based EDM in the Model Browser with the conceptual entity types
unfurled.

The top two nodes, Northwind and Northwind.Store, hold the conceptual model and store
model definitions respectively.
The properties of the Northwind node define critical code generation characteristics and merit
close attention on their own.
The balance of this topic takes you on a brief tour of the Model Browser. See the Microsoft
documentation for more detail.
Search
You can search in the Model Browser for an entity, property name, association, complex type,
store object ... just about anything ... by entering some text in the search TextBox at the top.
We look for "Company" in this screenshot:

Notice it found "Company" in the name of a property of the Customer entity and in the name
of a column in the "Customer" table.
Notice also the two red stripes on the window's scroll bar, indicating the approximate location
of every mention of "Company". That's a valuable clue when trying to find something in a
large model.
Context Menu
Right-mouse-click any object in the Model Browser to get a context menu that is specific to
the object type. The entity object context menus look like this one; the store object context
menu is shown below.

Show in Designer is a particularly useful option because it takes you directly to the
corresponding graphical object in the canvas. That's crucial because some EDM functions -
such as delete - are only available on the canvas.
Table Mapping opens the Mapping Window and displays the mappings for the selected
entity.
Stored Procedure Mapping opens the Mapping Window and displays the stored procedure
mappings for the selected entity. DevForce can take advantage of Entity Framework support
for entity stored procedures.
Update Model from Database... is how the Data-First developer adds and updates entities
based on database schema. It launches the Update Model Wizard.
Generate Database from Model.. generates SQL scripts for creation of a database that
matches the current conceptual model. This is useful for the Model-First developer; the Data-
First developer can ignore it.
Validate checks the entire model and reports errors and warnings to the Visual Studio "Error
Window". EDMX validation is covered in another topic.
Properties opens the designer's Properties Window for the selected object which could be an
entity, association, complex type, storage object, or the model as a whole.
Conceptual model object properties
Each entity object has its own distinctive properties as depicted in these screenshots. Most of
the properties are editable. Their meaning and values are discussed in the Properties Window
topic.
Model
The model properties level, "Northwind" in this example, controls diagram appearance and
code generation for the EDM as a whole.

Entity property

Association

Storage objects
You can browse the store object to which the entities are mapped.

You can't change anything about the store objects; their properties are read-only.
Delete store object

You can drop a store table, view, or stored procedure from the Model Browser by selecting it
and picking delete from the item's context menu as seen here.

This little known feature is the only way to drop a table from within the EDM Designer when
there is no corresponding, mapped entity. Usually you delete the table when you delete the
entity. But you can opt out and just delete the entity; the table definition remains behind,
unmapped, in the storage section of the EDM. If you later decide that you don't want to map
the table at all, this is the way to get rid of it.
You are only deleting the store object from the model, not from the database.

EDM Designer properties
The EDM Designer presents a different properties window for each kind of object in the
model. This topic describes many of the properties of each conceptual model object types and
how to set them.


The EDM Designer Property window lists EDM control properties for EDM objects such as
entities, associations, complex types, store objects, and the model itself. Each kind of object
has its own list of properties, appropriate to its type.
The most important - and the only properties you can change - are the Conceptual Model
properties. The DevForce EDM Extension supplements this set with its own properties to
guide DevForce generation of entity class code.
This topic concentrates almost exclusively on the DevForce designer extension properties.
You can learn about the base designer properties from other sources.
EDM Property Sets
Five property sets correspond to the five kinds of Conceptual Model objects:
1. The Model itself
2. Entity
3. Property
4. Association
5. Complex Type
We only consider the first. The Complex Type has a Tag property but is otherwise
uninteresting. The Association is a worthy topic of its own but has no DevForce-specific
EDM properties.
Pin the Properties Window open throughout this exercise and sort by category.
Open the Model Browser; it's easier to review a model in the Model Browser than on the
design canvas.
Model EDM Properties
Select the Model-level node which is "Northwind" in this screenshot.

Property Description
DataSource Key
An arbitrary string name that ties this EDM to a single data source. At runtime,
DevForce uses this name to find the appropriate database and its connection string.
The code generator adorns each entity class with an DataSourceKey attribute that
specifies this name, thus binding the entity class to the model's datasource.
DevForce
Enabled
Whether DevForce should generate code for this model.
EntityManager
Name
Name of the model-specific, EntityManager subclass that is generated for this
model; see below.
Generate
Binding
Attributes
Whether to generate the binding attributes - BindableAttribute, DisplayAttribute,
EditableAttribute, and ReadOnlyAttribute - for each entity property. These
attributes can be suppressed at the property level.
Generate
Developer
Classes
Whether to generate for each entity an empty partial class file for developer
customizations. False by default. Such files are easy to create manually when
needed.
Injected Base
Type
Name of the custom base class to inject at the root of the entity model hierarchy;
see below.
Max. Classes per
File
An integer specifying the maximum number of entity classes to generate in a single
class file; see below.
Odata enabled
Whether model-specific EntityManager can be used as an OData DataService.
When enabled, DevForce adds attributes and code to the EntityManager to support
OData and adds OData library references to the project.
Tag An arbitrary string of your choosing. Use it to guide your custom code generation.
Validation
Attribute Mode
Whether to use DevForce Verification attributes or the .NET attributes from
System.ComponentModel.DataAnnotations when adding validation attributes to
entity properties. See the "Validation" topic to assess the merits of each choice.
EntityManager subclass
DevForce generates a custom EntityManager with model-specific members that derives from
the EntityManager. The signature for such an EntityManager looks like this:
C#
[IbEm.DataSourceKeyName(@"NorthwindIBEntities")]
public partial class NorthwindIBEntities : IbEm.EntityManager { ... }
VB
<IbEm.DataSourceKeyName("NorthwindIBEntities")>
Partial Public Class NorthwindIBEntities Inherits IbEm.EntityManager
End Class
The "EntityManager name" matters, especially in a project with multiple EDMX files. If a
single project has multiple EDMX files and all of the models share the same EntityManager
Name, then the code generator emits a series of partial class files that compile together to
form a single custom EntityManager class that spans those models.
If the models each have their own "EntityManager Name", each model gets its own
EntityManager subclass.
Injected base type
DevForce entity class must ultimately inherit from Entity. If the "Injected Base Type" is
blank, the entity classes generated from this model will either inherit directly from Entity or
from another class in the model.
You can insert your own base class between Entity and the other generated entity classes by
naming that class in the "Injected Base Type". There are rules about this class:
Your base class must inherit from Entity or from another class that inherits from Entity.
If the "Injected Base Type" name is a "qualified name" - meaning it contains a period ('.') -
then that class is assumed to exist, derives from Entity, and is in a referenced assembly of the
model project.
If the "Injected Base Type" is not "qualified" - its name does not contain a period - DevForce
generates a partial class file for the base class; the generated class inherits from Entity but is
otherwise empty.
In either case, DevForce generates model entity classes that derive from your base class
instead of Entity.
The reasoning is as follows. Your base class may reside in another project where it can be
shared with other models in other projects or even other applications. Such a class would have
its own namespace, hence the period in the class name.
On the other hand, you may prefer to define the base class in this project for this model.
Generating the base class as a partial class is harmless, guarantees that all model entity
classes really do derive from Entity, and ensures that the project will compile ... even if you
neglect to fill in the base class details in your companion partial class file.
Max. classes per file
Models with a large number of entities can sometimes result in generated code files that are
too large to be processed by the Visual Studio editor. This problem may be avoided by
generating code into more than one file. The Max classes per file setting will limit the
number of classes that are generated into a single file and will create as many files as are
necessary to meet the specified constraint for each file. The default value for this property is
100 but can be adjusted in either direction. If it is set to 1, then each generated file will
contain only a single class. Having many generated files is often a bad idea because of issues
involved with synchronizing many changed files within a source control system. We
recommend leaving this default as is unless you have a specific issue that requires changing it.
Entity EDM Properties
Select an Entity node such as Customer as shown in this screenshot.

Property Description
Can
Query
Whether the client is allowed to send a query to the server that returns or involves this
type. The choices are True, False, and Default. If True or False, the code generator adds the
corresponding ClientCanQueryAttribute to the entity class. Default is equivalent to True
and suppresses the attribute altogether. A custom server-side
EntityServerQueryInterceptor is the ultimate arbiter of the client's right to query the type.
CanSave
Whether the client is allowed to save entities of this type. The choices are True, False, and
Default. If True or False, the code generator adds the corresponding
ClientCanSaveAttribute to the entity class. Default is equivalent to True and suppresses the
attribute altogether. A custom server-side EntityServerSaveInterceptor is the ultimate
arbiter of the client's right to save instances of this type.
Tag An arbitrary string of your choosing. Use it to guide your custom code generation.
Query and save authorization example
In the following example, the developer specified that the client can query but not save
Customers. The developer left both authorization properties as Default for the Employee
entity.
C#
using IbEm = IdeaBlade.EntityModel;
...
[IbEm.ClientCanQuery(true)]
[IbEm.ClientCanSave(false)]
public partial class Customer : IbEm.Entity { ... }

public partial class Employee: IbEm.Entity { ... }
VB
Imports IbEm = IdeaBlade.EntityModel
...
<IbEm.ClientCanQuery(True)>
<IbEm.ClientCanSave(False)>
Partial Public Class Customer Inherits IbEm.Entity
End Class

Partial Public Class Employee Inherits IbEm.Entity
End Class
EDM Properties for Properties
Entity and ComplexType properties are each defined by a set of EDM properties. The EDM
properties for the Customer.CompanyName property are below:

Property Description
Getter The access mode for the property getter; see note on property accessibility
Setter The access mode for the property setter; see note on property accessibility
Attribute
suppression
A collection of settings that determine which of many possible attributes can be
generated for this property; see "Attribute suppression" below.
Bindable Mode
A hint to the UI about whether the property can be bound OneWay, TwoWay, or
None=not at all. It's the parameter to the DisplayAttribute which is generated for the
property unless suppressed.
Concurrency
Strategy
Whether this property participates in optimistic concurrency conflict detection and
if so how; see below
Display Name
A hint to the UI about what name to use when constructing a label or grid column
header for this property. It's the parameter to the BindableAttribute which is
generated for the property unless suppressed.
Tag An arbitrary string of your choosing. Use it to guide your custom code generation.
Attribute suppression
By default, the code generator adorns entity entity or complex type property with the
attributes that are appropriate for that property. The "appropriate" attribute depends upon
characteristics of the property such as whether a setter exists, if the property is nullable or not,
if it is a string of known length (see the "Facets" category of EDM properties), etc.
Model-level settings can suppress some of the attributes for all properties in the model. You
also can suppress attribute generation for each entity and complex type property individually
by opening the Attributes to Suppress collection and setting any of them to True.
The attributes you can suppress are:
Attribute Description
Bindable
Suggests to the UI how the property should be bound: OneWay, TwoWay, or
None=not at all.
DefaultValue Specifies the default value to use during new entity initialization.
DisplayName Suggests the text that the UI should use to write labels and grid column headers.
Editable Suggests to the UI whether it should enable editing of this property.
Key Whether this property participates in the EntityKey.
Metadata
Whether to look at the entity's companion metadata class for the attributes to adorn
the property.
ReadOnly Whether the property is read-only or read/write.
Validation Whether to generate validation attributes.
Remember: these setting enable or suppress attribute generation. They do not set the values of the
attributes. For example, setting Editable false suppresses the EditableAttribute; it does not disable
editability.
Finally, for ultimate control over attribute generation, you can write an entity metadata class
and set every attribute manually.
Concurrency strategy
The "Concurrency strategy" choices are described in a topic dedicated to concurrency. The
choice you make here appears in the generated property code as one of the parameters to the
property's DataEntityProperty constructor, as seen in this example:
C#
using IbEm = IdeaBlade.EntityModel;
...
// RowVersion's DataEntityProperty
public static readonly IbEm.DataEntityProperty<Customer, Nullable<int>> RowVersion
= new IbEm.DataEntityProperty<Customer, Nullable<int>>
("RowVersion", ..., ..., IbEm.ConcurrencyStrategy.AutoIncrement, ...);
VB
Imports IbEm = IdeaBlade.EntityModel
...
' RowVersion's DataEntityProperty
Public Shared ReadOnly RowVersion As New _
IbEm.DataEntityProperty(Of Customer, Nullable(Of Integer))
("RowVersion", ... , ..., IbEm.ConcurrencyStrategy.AutoIncrement, ...)
Entity property accessibility
The property getters and setters are public by default. You can choose the access mode -
Public, Internal, Protected, or Private - to control the visibility of the property outside the
class.
All four choices are available ... except in Silverlight. Silverlight prohibits non-public
reflection; that prohibition prevents DevForce from getting and setting entity data while
communicating with the server during queries and saves.
You can choose Internal, thus limiting access to classed defined within the model project and
to assemblies that are friends of the model project. You must also make the project's internals
visible to .NET assemblies.
Change member visibility
You can change visibility of entity classes and properties in the EDM Designer but special
rules apply for models used in Silverlight.


Class and property visibility
The generated Entity Data Model (EDM) classes and their members are Public by default.
That isn't always a good idea. Some classes shouldn't be changed or constructed. Some
properties should be read-only.
You can change the visibility of a class or property in the EDM Designer. Locate the object in
the Model Browser, open its Properties window, and find the "Code Generation" category.
Entity and property options differ:
Entity visibility

Property getter and setter visibility

You have four visibility choices: Public, Internal, Protected, or Private. You can pick any of
them if you don't intend to use the model in Silverlight.
Silverlight restrictions
In Silverlight your only viable options are Public and Internal.
Silverlight prohibits non-public reflection. Silverlight won't let DevForce reflect for Protected
and Private types which means DevForce won't be able to get and set entity data while
communicating with the server during queries and saves.
Pick Internal if you want to hide an entity or property in a model that you will use in
Silverlight.
Follow the same rule when writing an entity's default constructor.
Make project internals visible to DevForce
Silverlight normally prevents outside assemblies from accessing internal members. It makes
an exception when the assembly's internals are made visible to two .NET assemblies.
Add these attributes to the project's AssemblyInfo file.
C
#
// These allow the expression tree built by DevForce for certain complex queries to be processed
correctly
// in Silverlight. Without it, some complex queries may fail with a MethodAccessException.
[assembly: InternalsVisibleTo("System.Core,
PublicKey=00240000048000009400000006020000002400005253413100040000010001008d56c76
f9e8649383049f383c44be0ec204181822a6c31cf5eb7ef486944d032188ea1d3920763712ccb12d75f
b77e9811149e6148e5d32fbaab37611c1878ddc19e20ef135d0cb2cff2bfec3d115810c3d9069638fe4
be215dbf795861920e5ab6f7db2e2ceef136ac23d5dd2bf031700aec232f6c6b1c785b4305c123b37a
b")]
[assembly: InternalsVisibleTo("System.Runtime.Serialization,
PublicKey=00240000048000009400000006020000002400005253413100040000010001008d56c76
f9e8649383049f383c44be0ec204181822a6c31cf5eb7ef486944d032188ea1d3920763712ccb12d75f
b77e9811149e6148e5d32fbaab37611c1878ddc19e20ef135d0cb2cff2bfec3d115810c3d9069638fe4
be215dbf795861920e5ab6f7db2e2ceef136ac23d5dd2bf031700aec232f6c6b1c785b4305c123b37a
b")]
V
B
' These allow the expression tree built by DevForce for certain complex queries to be processed
correctly
' in Silverlight. Without it, some complex queries may fail with a MethodAccessException.
<Assembly: InternalsVisibleTo("System.Core,
PublicKey=00240000048000009400000006020000002400005253413100040000010001008d56c76
f9e8649383049f383c44be0ec204181822a6c31cf5eb7ef486944d032188ea1d3920763712ccb12d75f
b77e9811149e6148e5d32fbaab37611c1878ddc19e20ef135d0cb2cff2bfec3d115810c3d9069638fe4
be215dbf795861920e5ab6f7db2e2ceef136ac23d5dd2bf031700aec232f6c6b1c785b4305c123b37a
b")>
<Assembly: InternalsVisibleTo("System.Runtime.Serialization,
PublicKey=00240000048000009400000006020000002400005253413100040000010001008d56c76
f9e8649383049f383c44be0ec204181822a6c31cf5eb7ef486944d032188ea1d3920763712ccb12d75f
b77e9811149e6148e5d32fbaab37611c1878ddc19e20ef135d0cb2cff2bfec3d115810c3d9069638fe4
be215dbf795861920e5ab6f7db2e2ceef136ac23d5dd2bf031700aec232f6c6b1c785b4305c123b37a
b")>
DevForce adds these lines to the project's AssemblyInfo automatically when you first generate
your entity model. You may have to add them manually if you moved the model to a different
model project.
Set property default value
You can see and set a property's default value in the EDM Designer.
This screen shows that Customer.CompanyName has been given a default value of "--
unknown--".

The EDM Designer adds this default to the definition of the CompanyName property.
<Property Name="CompanyName" ... DefaultValue="--unknown--" />
The range of default values is constrained. For example, you can't enter a string that contains
characters such as '<' and '>' that are reserved in XML. You can't enter functions either.
DevForce code generation adds a corresponding DefaultValueAttribute to the generated
CompanyName property.
C#
[DefaultValue("--unknown--")]
public string CompanyName { ... }
VB
<DefaultValue("--unknown--")>
Public Property CompanyName As String ...
Finally, DevForce reads the attribute at runtime and records the default in its metadata.
The entity creation topic explains how this model default value is used.
Combine related values in a ComplexType
A ComplexTypeis a class composed of other entity data properties.


The ComplexType
A ComplexType is a way to represent complex data within an entity.
Consider the Northwind "Employee" table for example. The "Employee" table has FirstName
and LastName columns. These become simple data properties of the Employee entity.
The "Employee" table also has Address, City, Region, PostalCode and Country columns. In a
default mapping, the Employee entity would have five corresponding properties.
But conceptually, these five properties are a single thing, an "address". We'd like to treat them
as an Address object. We'd like to write anEmployee.Address and expect to get an Address
object in return. We'd like to be able to create a new Address object and assign it to
anEmployee.Address. We might add validation rules to the Address class that constrain the
PostalCode to values that are legitimate for the Region.
The Address in this example is a ComplexType and you can create it in the Entity
Framework's EDM Designer. Julie Lerman tells how in a blog post and Matthieu Mezil shows
how in his video.
Here is the Northwind Employee entity with an Address property as seen in the EDM
Designer:

It is not an entity
A ComplexType is not an entity. It doesn't map to a complete table row. It lacks a unique key.
It has no existence independent from the entity to which it belongs. A ComplexType is called
a "value type because it is entirely defined by the values it holds, in much the way that the
number "5" is a value type. There is no table of numbers and no row representing the value
"5". In this example there is no "Address" table either.
ComplexType reuse
As it happens, those same five address columns appear in two other Northwind database
tables: "Customer" and "Order".
You can re-map their address columns to the Address type as seen in this screenshot:

ComplexType classes
DevForce generates ComplexType classes into your code file as it does the entity classes. The
properties of the generated ComplexType classes are similar to generated entity properties and
they support notification, validation, and property interception as their entity cousins do. The
generated ComplexType classes are partial so you can extend them with custom logic as you
do your entity classes.
An instance has a parent entity
A ComplexType instance doesn't stand alone; it belongs to its parent entity. For example, the
Address of the "Nancy Davolio" Employee belongs to the "Nancy Davolio" Employee entity.
In DevForce , you can always ask a ComplexType for its parent.
C#
Assert.AreSame(nancy, nancy.Address.ComplexAspect.ParentEntity);

VB Assert.AreSame(nancy, nancy.Address.ComplexAspect.ParentEntity)
This "belonging" is a necessary consequence of a ComplexType. The City, Region, and other
properties of "Nancy's" address actually map to columns on the "Nancy" record in the
Employee table. There is no Address table in this case; only a subset of the Person table's
columns that we want to treat as an address.
It follows also that a data property that returns a ComplexType cannot be null. It's member
properties can be null - nancy.Address.City may be null. But the ComplexType data property
itself - nancy.Address - cannot be null.
Learn more
Learn more about how to create and work with ComplexTypes in the EDM designer.
Advanced modeling topics
DevForce supports more than the simple mapping of tables to entities we've already
discussed. Here we'll briefly discuss more advanced modeling topics using the Entity Data
Model (EDM) designer.


Data Providers
DevForce works with any of the ADO.NET data providers which support the Entity
Framework. You can find more information here.
Inheritance
DevForce supports all the forms of inheritance, table mapping and splitting that the Entity
Framework supports.
Microsoft walkthrough on Table per Hierarchy inheritance mapping
Microsoft walkthrough on Table per Type inheritance mapping
Microsoft walthrough on mapping an entity to multiple tables
Note that there may be performance implications with some of these techniques.
Stored procedures
DevForce supports stored procedures for both query and create, update and delete actions.
How to import a stored procedure for query
How to map insert, update and delete functions to stored procedures
Code sample on stored procedures
Stored procedure queries in DevForce
Complex types
We've discussed complex types separately in some detail, but here's additional information.
How to create a Complex Type
Many-to-many
DevForce supports many-to-many relationships in the same way as the Entity Framework. If
the join table in the database contains no extra payload then the EDM Designer defines only
an association in place of a "join entity". If the table contains payload (i.e., additional
properties other than the foreign keys) then an entity is created for the table.
Many-to-many relationships in EF
Adding and removing with many-to-many navigation properties
Code sample on many-to-many relationships
Cascading deletes
DevForce defines the same rules for cascading a delete on a relationship as the Entity
Framework does. When you want to automatically delete all of the child records of a parent
when the parent record is deleted you can specify the cascade delete rule. As with EF, it is
strongly recommended that you specify the cascade delete rules in both the conceptual model
and the database. The reason for this is that DevForce will delete only the related objects
currently loaded into the entity cache.
Handle cascaded deletes when saving
Code sample on cascading deletes
Cascading deletes in EF
Concurrency
DevForce supports optimistic concurrency via the Entity Framework. The EF allows you to
define one or more concurrency properties for your entities; DevForce extends this support by
also allowing you to define a concurrency strategy for each.
Managing concurrency during a save
Code sample on handling concurrency conflicts
Learn more
Learn more about the EDM wizard and designer.
Descriptions and walkthroughs on mapping and modeling tasks.
Model First in the EDM Designer
This topic introduces techniques for defining a Conceptual Entity Model in the Model First
style using the Visual Studio EDM Designer.


You can define a Conceptual Model for your Entity Data Model (EDM) without referring to a
database using the "Model First" approach. DevForce can generate entity classes from the
Conceptual Model alone. You can develop and test the application without a database using
an offline entity cache or a fake backing store populated with dummy data.
Add entities and associations
You begin "Model First" development with the EDM Wizard, choosing the "Empty model"
option.
Then you add entities and relationships directly to the designer canvas. The details are out-of-
scope for DevForce documentation. The techniques involved are covered in the standard
Entity Framework literature. You might start with these two resources and search the web for
more:
Model-First in the Entity Framework 4
Creating an Entity Data Model the Model-First Way
You work more extensively with the Properties window in "Model First" then you do in "Data
First". In "Data First" most of the properties are filled-in for you based on database schema
information and there is rarely cause to change those values. In "Model First" there is no
database schema; you specify the details of every property and association according to your
plan for the entity.
Foreign Key Associations only
You must create "Foreign Key Associations" when adding associations to your model.
"Data First" developers don't worry about this because the EDM Designer, once properly
configured, ensures that all associations added from the database are "Foreign Key"
associations.
A "Model First" developer must be alert to the issue potential for the EDM Designer to create
an "Independent" association unexpectedly.
The designer creates an "Independent" association if you uncheck the "Add foreign key properties..."
CheckBox in the "Add Association" dialog, something you might do if the foreign key property
happened to be already defined.
You must convert an "Independent" association to a "Foreign Key" association by adding a
"Referential Constraint".
Mapping to a Database
When you are ready to associate the application with a real database, you map the Conceptual
Model to that database. Right-mouse-click on the canvas after which you select "Generate
Database from Model...". The resources cited above walk you through the process.
The EDM Designer doesn't actually generate the database. It produces a "DDL script" (Data
Definition script) that can generate the database. You can play this script from within Visual
Studio or run it separately.
Beware! the generated DDL script deletes all objects from the existing database; all of the
database data will be lost. If you are using "Model First" to add new entities and tables to an
existing database and you want to use the DDL script, be sure to edit it carefully to ensure it
does no harm.
Above all else, make sure you backup the database before running any scripts!
Database generation works well in the beginning when you have don't have a real database
with real data and are less inclined to care about an optimal database structure. As the
application matures you won't want to use that DDL script. You are more likely to create the
table in the database in your own way with your own script even if you've separately designed
the corresponding entity in your EDM in "Model First" style.
You can still proceed "Model First". You "reconcile" with the database in a different manner.
You don't generate DDL Script. You "Update Model from Database..." instead and add the
new tables that correspond to the new entities as you would for "Data First". The designer
won't recognize the correspondence with your "Model First" entities. if you had created a
Customer entity in "Model First" and subsequently added a Customer table to your database,
the EDM Designer will add that table as Customer1.
Use this behavior to your advantage. Compare Customer and Customer1. When you are
convinced that the generated Customer1 is correct, (1) delete your "Model First" Customer
entity and (2) rename Customer1 to Customer.
We suggest you proceed deliberately, adding only one or two tables at a time.
DevForce EDM Designer extension
The EDM Designer only collects the information it needs for Entity Framework's native code
generator. DevForce needs more information in order to generate its own entity classes. The
DevForce EDM Designer extension adds features to the base EDM Designer that help the
developer provide that extra information.


Extension installed
From the Visual Studio menu pick Tools | Extension Manager ... and scroll the Extension
Manager dialog until you see:


The DevForce EDM Designer extension was installed with DevForce.
If you don't see this extension, DevForce isn't installed or the extension was uninstalled. In the latter
case, you can reinstall it. Shut down Visual Studio and, from the Windows Start menu, pick All
Programs | DevForce 2010 v6... | Tools | DevForce EDM Extension.
The extension changes the EDM Designer in two ways:
1. It adds new DevForce properties to the Properties panel.
2. It writes the property values into the conceptual model section of EDMX file as custom
annotations.
Annotations are the approved way to extend the CSDL according to the specification.
"Annotations allow applications to embed application-specific or vendor-specific information
into CSDL. The format does not specify how to process these custom-defined structures or
how to distinguish structures from multiple vendors or layers. Parsers of the CSDL MAY
ignore Annotations that are not expected or not understood."
DevForce extension properties
This screenshot shows the EDM Designer displaying information about an entity property.


The CompanyName property of the Customer entity has been selected in the diagram on the
left. The Properties window on the right displays the EDM object definition properties of that
CompanyName property, sorted by category.
In the middle of the Properties window is a new category, outlined in yellow, labeled
DevForce Code Generation. This category was added by the DevForce EDM Extension.
The properties in this category govern code generation of the CompanyName property.
The Display Name property is outlined in red with a value of Company Name. The
developer is telling DevForce to add a .NET DisplayAttribute to the Customers
CompanyName property when it generates the entity class code.
The DisplayAttribute is a standard .NET UI hint; a UI control could discover that attribute and create a
label with the words Company Name next to a TextBox. Many developers like to decorate their
entities with such UI hints.
The DevForce EDM Extension writes this advice as an annotation to the CSDL section in the
EDMX file. The CSDL definition of the CompanyName property looks like this:
XML <Property Name="CompanyName" Type="String" Nullable="false" MaxLength="40"
Unicode="true" FixedLength="false"
ib10:DisplayName="Company Name" />
The attribute ib10:DisplayName is the DevForce annotation. After code generation the
property looks like something like this:
C#
[Display(Name="Company Name", AutoGenerateField=true)]
public string CompanyName {...}
VB
<Display(Name:="Company Name", AutoGenerateField:=True)>
Public ReadOnly Property CompanyName() As String
...
End Property
Controlling code generation
DevForce Code Generation sections adorn every level of the CSDL specification. At the top
level are properties to control code generation for the model as a whole:


You can even turn DevForce code generation off and restore the Entity Framework default
generator.


Keep the Enabled setting on True and see what DevForce generates.
Enable / Disable the extension
You can enable or disable the extension itself from within the Visual Studio Extension
Manager. Disabling the extension both removes the DevForce properties from the designer
and disables DevForce code generation.

EDMX in Source Control
Last modified on April 15, 2011 12:11
The EDMX file is a precious asset that defines your Entity Data Model (EDM) and is the
source for generating your entity classes.
Of course you are using a Source Control System to safeguard your application assets. The
EDMX file is one of the most important application assets; please put it in source control
immediately.
One less obvious but critical point: only one person at a time can work on a given EDMX
file because it is almost impossible to merge changes from two versions of an EDMX file. If
two people work on the same EDMX at the same time and try to commit their changes, the
source control merge tool could corrupt the EDMX as it tries to merge their respective
changes.
It's no big deal when this happens with code files. Firstly, merging code files usually works; it
doesn't work with the EDMX ... just as it doesn't work for Web.config and App.config files.
Second, humans can read a code file and resolve conflicting text lines. A human wrote that
code and can understand what it should look like. XML files such as the EDMX tend to be
written by a program such as the EDM Designer. They are much more difficult to read,
understand, and repair.
Please treat the EDMX file as a binary file. Your source control system has a way of
distinguishing binary files from text files. Find out how to configure it so that an EDMX is
treated as a binary file.
Review the connection string
A "Data First" Entity Data Model (EDM) is related to a database by an Entity Framework
connection string. This topic shows you how to find and review the Entity Framework
connection string.


Visible in the designer
The EDM Designer shows the Entity Framework connection string in the "Properties"
window:

Hover the mouse over the "Connection string" value and it appears as a tool-tip.
Note the "Metadata Artifact Processing" value indicates that the CSDL, SSDL, and MSL files
are embedded as resources in the project assembly.
Stored in a config file
The connection string is not stored in the EDMX. It is held in a .NET configuration file. The
Entity Framework designer writes the connection string to the Web.config if model is created
in the web application project; it creates and writes the string to an App.config if the model is
created in its own project.
When deploying as a web application (e.g., as a Silverlight application), you must copy the
<connectionStrings> section from the App.config to the Web.config.
The XML for the connection string is the same in either file and might look something like
this:
XML <connectionStrings>
<add
name="NorthwindIBEntities"

connectionString="
metadata=res://*/DomainModel.csdl|res://*/DomainModel.ssdl|res://*/DomainModel.msl;
provider=System.Data.SqlClient;
provider connection string=
&quot;
data source=localhost;
initial catalog=NorthwindIB;
integrated security=True;
multipleactiveresultsets=True;
App=EntityFramework
&quot;"

providerName="System.Data.EntityClient" />
</connectionStrings>
The entire string must appear on a single long line. It's been wrapped on this page for legibility.
The config XML <connectionString> has three parts:
the name of the string within the configuration file
the Entity Framework connection string
the Entity Framework provider that interprets the string.
The name of this connection string, "NorthwindIBEntities", matches the DevForce data
source key name for the model. DevForce writes this data source key name into every entity
class generated from the model. That's how the DevForce runtime knows which database
holds entities of this type.
The inner Entity Framework connection string has parts of its own:
The location of the metadata artifact files
The database provider to use for persistence operations (here it is SQL Server)
The database connection string (a string within a string)
The "metadata" fragment tells us the names of the metadata artifact files. The "res://*/"
segment means these files are embedded as resources in the model assembly; there would be a
file path name if the artifact files were loose in the output folder.
The root name, "DomainModel" in this example, must match the EDMX file name.
If you rename the EDMX file, be sure to update the names of the metadata artifact files in this
string. The Entity Framework won't be able to find the artifact files if the connection string
has the old names.
Update Model from Database
When the database changes, your Entity Data Model (EDM) must change to match. This topic
shows how to update the model from the database using the Entity Framework Update
Model Wizard.


You probably shouldn't model every table in the database all at once. You'll add new entities
over time and, if you use the Data-First approach, you'll want to initialize those entities and
their mappings from information in the database just as you did when you first created the
model with the EDM Wizard.
The application is not static. New requirements arrive all the time and they often involve
changes to the database some of which you must incorporate into your model.
Please don't start over.
That can be tempting. But if you do, you'll lose all of the changes you made along the way.
These changes are in your EDMX file and there is no easy way to find and merge them into a
new EDM.
Instead you use the Entity Framework Update Model Wizard to add new entities to your
model and to update previously mapped entities when their corresponding database objects
have changed.
Here we only touch upon the issues that are of most concern to the DevForce EDM developer.
You can learn more about the Update Model Wizard from Microsoft's documentation on
MSDN.
Using the Wizard
You can update your model anytime. Right-click on the canvas and select Update Model
from Database.... This launches the Entity Framework Update Model Wizard as seen here.
Always, always, always backup the EDMX before you update the model from the database.

1. Select the tables to model as entities. The wizard only shows tables (and views) that are not
already modeled in your EDM. You can only model a database object once.
2. Keep Pluralize or singularize generated object names checked if you want to continue using
the English language pluralization rules; these are the same rules used by the EDM Wizard.
3. Keep Include foreign key columns in the model checked. All associations in a DevForce EDM
must be "Foreign Key Associations".
When the wizard closes:
New entities appear for the tables and views that you added.
New properties appear for columns added to tables that are already entities in your model.
New properties appear if columns were renamed. The entity property mapped to the old
column remains in the model
Beware of delete and rename
The Update Model Wizard never deletes and never renames anything in your
conceptual entity model.
The wizard only adds new items and removes mappings that it no longer understands.
If you drop the "Customer" table from the database and it was formerly mapped to the
Customer entity, the Customer entity remains in your model ... where it is now unmapped
because the wizard can't find the matching database table.
If you renamed the "Customer" table to "Company", the "Company" table appears in the list
of objects you can model. The wizard doesn't know that you already modeled that table under
its old name.
When you select the "Company" table in the wizard, the wizard adds a new Company entity to
your model. It also preserves the Customer entity which is unmapped because the wizard can't
find the matching table.
The same dynamic applies to properties. If the "CompanyName" column was deleted,
Customer.CompanyName remains although it is no longer mapped. If the column was
renamed to "CustomerName", there will be a new property, Customer.CustomerNamethat is
mapped to that column. The old Customer.CompanyNamesurvives as an unmapped property
as well; you'll have to delete it manually.
Be very careful when deleting or renaming primary and foreign keys columns. The
wizard doesn't understand what you are doing. Existing properties and associations will
become unmapped and new key properties will appear.
An entity that once had a single part key will have a composite two part key: the old key
property under the old name and the new key property under the new name property. This
change cascades to the associations that depend upon that key.
You will have to make manual repairs when you delete or rename anything in the
database.
The model will not validate until you repair the model and the entity classes generated from
the model will be incorrect until you do. Pay attention to the EDM error messages. They can
be a little confusing. You can power through it if you know what changed in the database and
remember that the wizard only adds, never deletes.
We recommend that you modify the database incrementally, making a small change and then
updating the model immediately. This is particularly important when renaming or deleting
database objects that you have previously mapped to your EDM.
Storage and mapping sections are regenerated
The wizard's guiding principal is that the conceptual entity model is yours. That's why it only
adds to the conceptual entity model; it won't remove or change anything in the conceptual
model.
However, the wizard acts as if it owns the storage and mapping schemas. You should assume
that the wizard rewrites everything in the mapping and storage schemas. Of course it reads
your previous mappings and preserves them if it understands them. But if it erases anything it
doesn't recognize or that conflicts with its reading of the database schema.
You cannot control this behavior. You cannot tell the wizard "refresh these entities but leave
those alone." The wizard reevaluates your entire model ... and rewrites the storage and
mapping sections as it sees fit.
This fact is especially relevant if you have made manual changes to the storage or mapping
sections of the XML. Pay particular attention to the section "Entity Framework Features Not
Supported by the Entity Designer" in the Microsoft documentation of the EDM Designer.
You can work around those limitations by editing the XML directly to implement features the
designer doesn't support. Just remember that the wizard probably will erase those changes.
You will have to restore them from your backup of the edmx file.
Edit the EDMX as XML
This topic shows how to open and edit the Entity Data Model's EDMX file in the Visual
Studio XML editor and describes its basic structure.


The Entity Framework EDM Designer is sufficient for most of your Entity Data Model
(EDM) development work.
The design tool can't do everything. Some times you have to edit the XML file - the EDMX -
in a text editor either because the design tool doesn't support a feature or because it is more
efficient to perform a repetitive editing chore in the raw XML.
Open the EDMX in Visual Studio
A search of the web may be the best way to learn how to edit and understand the EDMX
XML. The MSDN documentation is a good place to start.
Here are brief instructions and an overview:
Select the EDMX file in the "Solutions Explorer" window
Pick "Open With..." from the context menu
Open with the "XML (Text) Editor"
The EDMX XML appears. Even a small model can produce thousands of lines of XML. It's
actually semi-readable and navigable when you know the basics.
To get a handle on it, use the "Outlining" feature to collapse the sections.
Pick from Edit | Outlining | Toggle All Outlining from the menu or use the keyboard
shortcut, Ctrl-M, L.
Unfold the first level to reveal the "Runtime" and "Designer" sections.
Unfold the "Runtime" section to reveal the "SSDL", "CSDL", and "C-S" sections

EDM sections
The four major sections of an EDMX are now neatly arranged before you. Only the first
three, the ones grouped under "Runtime", pertain to the Entity Data Model:
SSDL Storage Schema Definition describes the database schema (tables and columns).
CSDL Conceptual Schema Definition describes entities (types and properties).
C-S Conceptual-Storage Mapping maps conceptual entities to storage objects.
The storage schema describes the objects in the database. The storage model XML language
is database-neutral; it could describe a Microsoft SQL Server schema or MySQL schema
or Oracle schema. The Entity Framework is open to many database products any database
product for which there is an EF Data Provider. Most popular relational database products
have an EF Data Provider. Of course EF provides its own SQL Server Data Provider out-of-
the-box; you can search the web for other providers for other databases.
The conceptual schema defines a Conceptual Entity Model in terms of entity types and their
properties. The conceptual model XML language is implementation-neutral. It doesnt
prescribe a particular representation in code. A reporting engine might use it to create reports.
WCF Data Services uses it to produce XML representations and JSON objects to OData
consumers. Anyone can read the conceptual schema and interpret it.
The typical Conceptual Model interpreter is a tool that generates .NET entity classes. The
Entity Framework ships with a primary code generator that runs automatically every time you
save changes to the EDM. You can replace that default generator with your own code
generator and DevForce does just that.
Metadata Artifact Files
Entity Framework takes the three EDM sections of the EDMX - the conceptual model, storage
model, and mapping XML - and splits them out into separate files. These are the Metadata
Artifact Files.
The "Metadata Artifact Processing" property, visible in the EDM Designer properties
window, determines how these files are deployed; they are either embedded in the model
assembly as resources (the default) or copied to the output directory as loose files.

We see in this example (using a reflection tool) that the artifact files are embedded:

The artifact files are easier to manage when embedded so keep them that way unless you have
a compelling reason to do otherwise.
Designer section
The fourth, Designer section tells the EDM Designer how to draw the diagram on the design
canvas. It also specifies values for some of the options that influence the behavior of the
designer. Here's a screen shot:

You are unlikely to edit the diagram in XML. If you've made a mess of your model diagram
or your source control system corrupts it during a merge (it happens), you can erase the
contents of the <Diagrams> section; the EDM Designer will recover and create a new
diagram.
The options are another matter. Most of them can be modified within the EDM Designer. The
IncludeForeignKeysInModel cannot be set in the designer and you may need to add that
property manually to restore Foreign Key Associations as the default association creation
strategy.
Foreign Key Associations required
Entity Framework v.4 supports two kinds of associations: "Independent" and "Foreign Key".
All associations in a DevForce model must be "Foreign Key Associations".


Foreign Key Associations only
The Entity Framework v.4 supports two types of association, "Foreign Key Associations" and
"Independent Associations".
"Independent" associations were the only type of association in version 1 of EF.
"Independent" associations hide their foreign keys and they lack a "Referential Constraint"
section in their XML definitions.
Here's an example:
XML <Association Name="CustomerOrder">
<End Type="DomainModel.Customer" Role="Customer" Multiplicity="1" />
<End Type="DomainModel.Order" Role="Order" Multiplicity="*" />
</Association>
DevForce cannot work with these key-less "Independent" associations. All associations must
be the "Foreign Key" type that was introduced in EF version 4. "Foreign Key" associations
expose their foreign keys and have a "Referential Constraint" section as seen in this EDMX
fragment.
XML <Association Name="FK_Order_Customer">
<End Type="DomainModel.Customer" Role="Customer" Multiplicity="0..1" />
<End Type="DomainModel.Order" Role="Order" Multiplicity="*" />
<ReferentialConstraint>
<Principal Role="Customer">
<PropertyRef Name="CustomerID" />
</Principal>
<Dependent Role="Order">
<PropertyRef Name="CustomerID" />
</Dependent>
</ReferentialConstraint>
<Association>
Check "Include foreign key columns" in the EDM Wizard
When you first created your EDM with the EDM Wizard and chose the "Data First" modeling
approach, you were required to check the CheckBox next to "Include foreign key columns".
"Include foreign key columns" is especially critical. If you uncheck the option by accident,
the "Update Model from Database" wizard creates new associations as "Independent"
associations. You have to fix that.
You must restore the "Foreign Key" option. You can turn it back on in the "Update Model
from Database..." wizard while adding a new object to the model
Or you can add the option in XML by editing the EDMX.
Open EDMX file in the "XML (Text) Editor"
Locate the EF Designer section (it's the last section)
Locate the "<Options>" subsection (near the top of the EF Designer section)
Add the "IncludeForeignKeysInModel" designer property as seen here
XML <Options>
<DesignerInfoPropertySet>
<DesignerProperty Name="ValidateOnBuild" Value="true" />
<DesignerProperty Name="EnablePluralization" Value="True" />
<DesignerProperty Name="IncludeForeignKeysInModel" Value="True" />
</DesignerInfoPropertySet>
</Options>
Save and close the EDMX editor
You have to manually fix all associations that you created before re-engaging "Foreign Key
Associations" as discussed in the "Model First" topic.
Converting to a Foreign Key Association
You must convert all existing "Independent" association to a "Foreign Key" association by (a)
adding the foreign key properties manually and (b) adding a "Referential Constraint".
Open the "Referential Constraint" dialog either by double-clicking the Association line in the
diagram or pressing the button in the "Referential Constraint" property.

Then fill in the blanks as in this example:















Generate model code
Generate entity class code from an Entity Data Model (EDM) prepared with the Entity
Framework EDM Designer.


Model project changes
Add an Entity Framework Entity Data Model (EDM) to a project and examine the project in
the Visual Studio "Solution Project" window.
Examples in this topic are based on a separate model project rather than the web application
project seen in many tutorials. The model project is free of unrelated artifacts which makes it
easier to focus on specifics of the model. The principles are the same for either kind of
project.

The EDM Wizard and DevForce code generation have made significant changes to the
project:
1. The EDM Wizard added Entity Framework assembly references; DevForce added its assembly
references.
2. The EDM Wizard added an Entity Framework connection string to the App.config or to the
Web.config if had been a web application project.
3. The EDM Wizard added the EDMX file of XML that describes your model. You fleshed out
that model with the EDM Designer.
4. DevForce added the code generation template file with the .tt extension.
5. DevForce generated the nested source code file with the ".Designer.cs".
DevForce used the T4 code generator built into Visual Studio to create the source code file.
Source code files are regenerated automatically every time you save a change to the
EDMX file.
You can also regenerate manually by selecting the .tt template file and choosing Run
Custom Tool from the context menu.
DevForce code generation template
The T4 code generator is directed by the DevForce code generation template which reads the
EDMX and emits entity model source code file(s). The template file name shares the same
root name as the EDMX file, SimpleNorthwind in this example.
Entity Framework (EF) has its own T4 template (several templates actually). The DevForce template
replaces EF's template when DevForce tooling is installed and enabled. You can restore EF code
generation, perhaps to see how the code files differ, but your application probably won't work until
you re-enable DevForce code generation.
The DevForce template only needs the CSDL section of the EDMX file because the .NET
entity classes are entirely described by the conceptual entity model. That's why a DevForce
entity class model can be designed in the Model First style which only has a CSDL.
Generated source code files
There is only one generated source code file in this small example,
SimpleNorthwind.IB.Designer.cs. There could be several generated source code files if the
model were unusually large. You control the number of classes generated per file - and hence
the number of files - by setting the "Max. Classes per File" model property in the EDM
Designer.
Inside a source code file
Never modify a generated source code file by hand. When the file is regenerated as it inevitably will
be all of your changes will be lost. There are other ways to customize the generated source code.
The following snapshot of a generated class file shows three kinds of classes.

At the top is a model-specific EntityManager component. The EntityManager is the most
important component in all of DevForce and you will get to know it well.
Below that are the generated entity classes, one after another, each one generated from the
conceptual entity defined in your EDM.
DevForce generates true Entity Framework classes. You can perform pure Entity Framework
operations with these class using EF's ObjectContext in textbook fashion. But the DevForce
entity classes differ significantly in their support for distributed application scenarios,
validation, property interception, and UI data binding.
The Customer class is typical:

Finally, at the bottom, is the EntityRelations class
C#
/// <summary>
/// A generated class that returns the relations between entities in this model.
/// </summary>
public partial class EntityRelations : IbEm.IEntityRelations { ...
VB
''' <summary>
''' A generated class that returns the relations between entities in this model.
''' </summary>
Partial Public Class EntityRelations Inherits IbEm.IEntityRelations ...
EntityRelations defines every relationship between every entity in the model.
Customize the code generation template
In general you customize the generated classes by adding more code to the model. You can
trim back some of the emitted code by adjusting the generator control properties within the
EDM Designer. You can replace all of the attributes with an entity metadata class.
If these paths prove insufficient, you can customize the code generation template yourself.
Generated EntityManager
The DevForce code generator creates a model-specific subclass of the DevForce
EntityManager that is specific to the application's entity model and therefore easier to work
with. You'll find it at the top of the generated class file.
It might look something like this
C#
/// <summary>
/// The domain-specific EntityManager for your domain model.
/// </summary>
[IbEm.DataSourceKeyName(@"NorthwindEntities")]
public partial class NorthwindManager : IbEm.EntityManager { ...
VB
''' <summary>
''' The domain-specific EntityManager for your domain model.
''' </summary>
<IbEm.DataSourceKeyName(@"NorthwindEntities")>
Partial Public Class NorthwindManager Inherits IbEm.EntityManager ...
The EntityManager is the most important component in all of DevForce and you will get to
know it well. It is the portal to the server, the vehicle for queries and saves, and manages the
container of entities (the entity cache) that reside in application memory.
It is not part of the model. It is machinery that uses the model but it is not of the model itself.
You really dont need a custom subclass of the EntityManager - not the way you need the
entity classes. You can do without it. You can use the base EntityManager class for
everything and sometimes thats exactly what youll want to do.
DevForce generates one anyway because it is often more convenient to work with a custom
EntityManager that is enriched with dedicated model properties than to use the base
EntityManager.

The collection of custom IdeaBlade.EntityModel.EntityQuery<T> properties is a case in
point. You can write a query to retrieve all Customers using an instance of any EntityManager
like this:
C# query = manager.GetQuery<Customer>(); // a Customer query for any EntityManager
VB query = manager.GetQuery(Of Customer)() ' a Customer query for any EntityManager
The same query is easier to read and write when we use an instance of NorthwindManager,
the custom EntityManager tailored to this specific model:
C# query = manager.Customers; // the Customer query predefined for this model
VB query = manager.Customers ' the Customer query predefined for this model
Finally, notice that NorthwindManager is a partial class that you can extend to suit your
needs.
Generated entity classes
Aside from the custom EntityManager, the rest of the generated source code file concerns the
entity model and all most all of the file consists of entity class definitions. This topic offers
an orientation to the code generated for the Customer class shown in this screenshot.



Attributes
The attributes leap out at you. Those familiar with Window Communication Foundation
(WCF) will recognize DataContract and KnownType, attributes that guide serialization.
DevForce-generated entities are ready for serialization and not just by DevForce itself as it
shuttles entities between server and client. You can serialize entities in your own way for your
own purposes as well (e.g., to a file for safe keeping).
The DataSourceKeyName is a DevForce attribute that identifies symbolically the data source
where the Customer entity data are stored.
IbEm is an alias for the DevForce IdeaBlade.EntityModel namespace. Namespaces appear repeatedly
throughout the file; the alias helps reduce the file size.
Why would we mark each entity class with its data source? Why not denote the data source at
the model level?
Because DevForce can mix entities from different data sources in the same container. We can
mix entities from Database A and entities from Database B in the same EntityManager
cache. We can save changes to those entities too; DevForce will arrange a distributed
transactional save on the server.
DevForce Entity base class
The Customer entity inherits from the DevForce Entity class:
C# public partial class Customer : IbEm.Entity {...}
VB
Partial Public Class Customer
Inherits IbEm.Entity
...
End Class
All generated entity classes inherit (ultimately) from the Entity class whose primary functions
concern change tracking and access of entity state.
The Entity base class is no serious threat to "testability" or "extensibility". You can "new" a
Customer in test environments without creating or mocking a dependency. Entity itself does
not have any persistence functions. It doesnt query or save. It is persistence ignorant in this
strict sense.
It may hold a reference to the EntityManager to which it is attached (if, in fact, it is attached);
you can "new" a fully functioning and self-sufficient test EntityManager/ in a single line.
True, your Customer is DevForce framework aware and your model project must refer to
DevForce libraries. You need those references for a functioning system in any case.
You also can inject your own custom entity base class into the entity model inheritance
hierarchy
Data properties
The properties defined within the Properties region provide access to persistent data. As such
they are often called data properties to distinguish them from the other inhabitants of the
property zoo.
Data properties are the .NET manifestations of the entity properties described in the CSDL
section of the entity data model (EDM).
Each data property returns a single instance of a type, usually a simple .NET type such as
string or int. A property that returns a simple .NET type can return null if the property is
nullable. It could return a ComplexType - an encapsulation of multiple data values in a single
type; ComplexType data properties never return a null value.
All data properties in this example return simple .NET types as illustrated by the
Customer.CompanyName property:
C#
[Bindable(true, BindingDirection.TwoWay)]
[Editable(true)]
[Display(Name="Company Name", AutoGenerateField=true)]
[IbVal.StringLengthVerifier(MaxValue=40, IsRequired=true,
ErrorMessageResourceName="Customer_CompanyName")]
[DataMember]
public string CompanyName {
get { return PropertyMetadata.CompanyName.GetValue(this); }
set { PropertyMetadata.CompanyName.SetValue(this, value); }
}
VB
<Bindable(True, BindingDirection.TwoWay), Editable(True), _
Display(Name:="Company Name", AutoGenerateField:=True), _
IbVal.StringLengthVerifier(MaxValue:=40, IsRequired:=True, _
ErrorMessageResourceName:="Customer_CompanyName"), DataMember>
Public Property CompanyName() As String
Get
Return PropertyMetadata.CompanyName.GetValue(Me)
End Get
Set(ByVal value As String)
PropertyMetadata.CompanyName.SetValue(Me, value)
End Set
End Property
The profusion of attributes may seem disturbing. There are more attributes adorning the
property than there are lines of code within it!
The attributes help the entity fulfill the multiple roles we expect it to play on both client and
server. Bindable, Editable, and Display are hints to UI tooling that affect how user controls
are chosen and configured. The StringLengthVerifier is a validation rule derived from
constraints expressed in the CSDL. DataMember is WCF markup indicating that the value of
this property should be serialized.
You can alter or remove all of the attributes except DataMember by suppressing them in the
EDM designer and by adding alternative annotations in a metadata buddy class.
The property is public by default. You can make it less accessible in the EDM designer.
Caution: properties of entities used in Silverlight must be public or internal. Because Silverlight
prohibits access to protected and private properties, DevForce couldnt read or write the property
when serializing to a Silverlight client.
The get and set implementations are one-liners that delegate to a member of the entitys inner
PropertyMetadata class. The PropertyMetadata class is an advanced topic beyond the scope
of this overview. But we can infer some of its capabilities by looking at how it is called within
a property definition.
C#
get { return PropertyMetadata.CompanyName.GetValue(this); }
set { PropertyMetadata.CompanyName.SetValue(this, value); }
VB
Get
Return PropertyMetadata.CompanyName.GetValue(Me)
End Get
Set
PropertyMetadata.CompanyName.SetValue(Me, value)
End Set
The property is relying on helper methods to perform functions that go beyond simple value
access. In fact, each helper method establishes a property value pipeline one going in and
one going out that can do more than access a backing field. The setters in-bound pipeline
can intercept values, validate them, and raise events such as PropertyChanged. The getters
out-bound pipeline allows the developer to intercept values on their way out.
Property interception, validation, and change notification are vital DevForce features that
grant the developer fine-grained control over the behavior of an entity at the property level.
The simple, one-line syntax conceals the potential for extending the property behavior with
custom business logic logic that might be part of the class definition or might be injected
dynamically from sources outside the class.
Navigation properties
A navigation property is a means to retrieve an entity (or a list of entities) to which this entity
is related by an association. The association was defined in the Entity Data Model (EDM).
In this example, the Customer has an Orders property that returns a list of Orders. For a given
customer, the Orders property returns the order placed with that customer.
When we exercise the Orders property we say we navigate from the customer to its orders.
Here is its implementation:
C#
[Bindable(false)]
[Display(Name="Orders", AutoGenerateField=false)]
[DataMember]
[IbEm.RelationProperty("FK_Order_Customer", IbEm.QueryDirection.ToRole1)]
public IbEm.RelatedEntityList<Order> Orders {
get { return PropertyMetadata.Orders.GetValue(this); }
}
VB
<Bindable(False), Display(Name:="Orders", AutoGenerateField:=False), _
DataMember, IbEm.RelationProperty("FK_Order_Customer", IbEm.QueryDirection.ToRole1)>
Public ReadOnly Property Orders() As IbEm.RelatedEntityList(Of Order)
Get
Return PropertyMetadata.Orders.GetValue(Me)
End Get
End Property
We have attributes as we did for the data properties.
One attribute in particular identifies both the association (called a relation in DevForce) and
the direction of the association. That tells DevForce that you are navigating from the
Customer to the Orders. More on Associations in a moment.
The Orders navigation property is significantly different from the CompanyName data
property we reviewed earlier. Orders returns a list of entities, not a data value. The entities
could come from the local cache or the get could trigger so-called lazy loading of orders from
the server; whether the property does or does not lazy load is dynamically configurable.
A lazy load operation is performed asynchronously in Silverlight. The property immediately returns a
list of whatever related orders (if any) happen to be in cache; the list could be empty. Meanwhile,
the attached EntityManager asks the server for the related orders in background. When the orders
arrived, the EntityManager populates the list. The list raises events. A watchful UI could respond to
those events by filling the screen with orders.
Notice that the get implementation delegates to the PropertyMetaData class just as the data
property did. The Orders.GetValue is a pipeline the developer can control and intercept with
logic of his own.
Notice that there is no set. The Order property is read-only. Orders is a collection navigation
property, a navigation returning a list of entities. The developer can add and remove entities
from the list but cannot replace the list itself.
There is another kind of navigation property - the reference navigation property that returns
a single entity. This particular Customer entity doesnt have a reference navigation. We
suspect that Order does have a reference navigation property one that navigates back from
the order to its parent Customer.
We suspect such a property exists but we cannot be sure without looking. Navigation
properties are optional. You can choose to omit navigation properties from code generation.
The association between Customer and Order would remain even if you opted out of both
navigation properties.
In this case, Order does have a Customer property.
Here is Orders Customer property
C#
[Bindable(false)]
[Display(Name="Customer", AutoGenerateField=false)]
[DataMember]
[IbEm.RelationProperty("FK_Order_Customer", IbEm.QueryDirection.ToRole2)]
public Customer Customer {
get { return PropertyMetadata.Customer.GetValue(this); }
set { PropertyMetadata.Customer.SetValue(this, value); }
}
VB
<Bindable(False), Display(Name:="Customer", AutoGenerateField:=False), _
DataMember, IbEm.RelationProperty("FK_Order_Customer", IbEm.QueryDirection.ToRole2)>
Public Property Customer() As Customer
Get
Return PropertyMetadata.Customer.GetValue(Me)
End Get
Set(ByVal value As Customer)
PropertyMetadata.Customer.SetValue(Me, value)
End Set
End Property
It has both a get and a set. That means we could set the parent Customer as well as retrieve it.
The get could trigger a lazy customer load if the parent customer is not in cache.
DevForce can also lazy load a reference navigation property asynchronously in Silverlight. The
property immediately returns a special form of the Customer entity instance called a PendingEntity .
This instance has placeholder values until the actual customer data arrive from the server.
A reference navigation property always returns a value, never a null. If an order has no parent
customer, the property returns a special Customer entity called the Null Entity (aka, nullo).
The null entity reduces the likelihood of null reference exceptions and eliminates much of the
null value checking that plagues the typical code base.
The null entity has permanent placeholder values; all of its reference navigation properties
return null entities as well so you can have long chains of navigations
(order.Customer.SalesPerson.Name) without incurring a null reference exception. You can
always as an entity if it is the null entity.
Finally, the promised word about Associations. Associations (Relations) are inherently
bidirectional. A Customer has Orders; each Order has a Customer. When defining a
navigation property we have to say which way were going: from customer to orders or from
orders to customer. The Role (either Role1 or Role2) indicates the direction.
You can usually guess which entity type is Role1 and which is Role2 by the name of the
RelationProperty (e.g., FK_Order_Customer). To be certain, you must look at actual definition of that
RelationProperty in the generated class called EntityRelation. Youll always find the EntityRelation
class at the bottom of the generated code file.
DevForce supports the same cardinality of Associations as Entity Framework. They can be 1
1, 0..1 1, 1 0..1, 0..1 M, M 0..1, and M M.
Yes, DevForce supports many-to-many, unlike WCF RIA Services.





Restore Entity Framework code generation
Last modified on March 25, 2011 15:41
DevForce "turns off" Entity Framework code generation by clearing the Custom Tool
property setting associated with the EDMX file.
If you need to re-enable Entity Framework code generation, open the EDMX file in the EDM
Designer and set the DevForce Enabled flag to false, then save the file. This action
resets the Custom Tool to EntityModelCodeGenerator,
removes the DevForce-specific files, and
runs Entity Framework code generation.
Your DevForce application won't work with entities generated by the Entity Frameworks'
templates.
Remember to reset the DevForce Enabled flag back to true to re-enable DevForce code
generation.
Customizing the DevForce code generation template
Customize the DevForce code generation template when you need fine control over the
entity class code generated for your Entity Data Model (EDM).


DevForce code generation uses the .NET Text Template Transformation Toolkit (T4) to
customize code generation. DevForce ships with a default T4 template that is used for all code
generation. Like most T4 templates provided by Microsoft and other vendors, this template
can be replaced with a custom version. Custom versions are usually a copy of the default
template with some minor modifications.
While DevForce supports this approach, we provide what we believe to be a better approach.
Instead of modifying the template, you subclass the core template generator class,
DomainModelTemplate, overriding only those portions which requires custom treatment.
Virtually every major code generation region within your generated code corresponds to a
virtual method within this class.
Deriving from DomainModelTemplate is much easier than writing raw T4 source code:
You write in a familiar programming language
You'll have substantially less code to maintain.
IdeaBlade frequently releases improved versions of DomainModelTemplate with new
features and fixes.
DomainModelTemplate can generate either C# or VB code from a single template file.
Debugging a DevForce template is substantially easier than debugging a standard T4
template.
The source code for DomainModelTemplate is shipped with DevForce; find it in the
DevForce installation directory.
The DevForce template
When you add an Entity Framework EDMX, DevForce adds its T4 template to the project,
modifying it slightly to reflect the specifics of your model. A typical example looks
something like the following:
T4 <#@ template language="C#" debug="true" hostSpecific="true" #>
<#@ output extension="./DontReadMe" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="IdeaBlade.VisualStudio.DTE.dll" #>
<#@ Assembly Name="IdeaBlade.VisualStudio.OM.CodeGenerator.dll" #>
<#@ Assembly Name="IdeaBlade.EntityModel.Edm.Metadata.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="IdeaBlade.VisualStudio.DTE" #>
<#@ import namespace="IdeaBlade.VisualStudio.OM.CodeGenerator" #>
<#@ import namespace="IdeaBlade.EntityModel.Edm.Metadata" #>
<#
// Source for this file located at:
// C:\Users\...\AppData\Local\Microsoft\VisualStudio\10.0\Extensions\IdeaBlade,
Inc\
// IdeaBlade OM Designer Extension\6.0.5.0\DomainModelTemplate.tt
// SimpleNorthwind.edmx <--- Needed so "Transform Related Text Templates On
Save" works correctly.
var template = new DomainModelTemplate(this);
template.Generate();
#>
<#+
#>
The template delegates the work to
IdeaBlade.VisualStudio.OM.CodeGenerator.DomainModelTemplate class about five
lines from the bottom..
There are three steps to customizing this template:
1. Subclass DomainModelTemplate within the existing .tt file.
2. Make a template from the modified .tt file
3. Move your custom DomainModelTemplate to its own assembly.
You get a working template at every step. You can stop after steps #1 or step #2 if you wish.
We recommend you go all the way to step #3.
Before starting, you must install the Visual Studio 2010 SDK to get the
Microsoft.VisualStudio.TextTemplating library. Install the right SDK for you version of
Visual Studio, either Visual Studio 2010 or Visual Studio 2010 SP1.
#1 Subclass inside the .tt file
You are going to subclass the DomainModelTemplate class inside the project's .tt file.
First, add two assembly references
Microsoft.VisualStudio.TextTemplating.10.0
IdeaBlade.Core
Next, find the declaration of the template variable and set it with your new template generator
class
Finally, write the code for your template generator class directly below the old code as seen in
this example:
T4 <#@ template language="C#" debug="true" hostSpecific="true" #>
<#@ output extension="./DontReadMe" #>
<#@ Assembly Name="Microsoft.VisualStudio.TextTemplating.10.0" #>
<#@ Assembly Name="IdeaBlade.Core" #>
...
// SimpleNorthwind.edmx <--- Needed so "Transform Related Text Templates On
Save" works correctly.
var template = new MyTemplate(this);
template.Generate();
#>
<#+
public class MyTemplate : DomainModelTemplate {

public MyTemplate(Microsoft.VisualStudio.TextTemplating.TextTransformation
textTransformation)
: base(textTransformation) {}

protected override void WriteEntityDataPropertyAttributes(EdmPropertyWrapper
property) {
WriteAttribute("Foo(" + Quote(property.Name) + ")");
base.WriteEntityDataPropertyAttributes(property);
}
}
#>
This customization simply adds a Foo attribute to the top of every data entity
property.
MyTemplate() replaces DomainModelTemplate and overrides the base
WriteEntityDataPropertyAttributes method to add Foo.
See the topic on adding a custom base class for a more realistic example of a template method
override that also makes use of the Tag EDM extension property.
While writing the MyTemplate class within the template itself is certainly easy to do, we don't
recommended it.
First, this customization only works for the specific EDMX to which it is attached.
SimpleNorthwind.edmx, the name of this project's EDMX file, is baked into the .tt file. If you
change the name of the EDMX file you'll have to change change this .tt file as well. You
won't be able to re-use this custom MyTemplate class for other models and applications.
Second, you don't get any help from Intellisense while you're writing MyTemplate; it's
difficult to edit a template file with any significant amount of code this way.
Let's fix the first problem first.
#2 Make a template from the modified .tt file
The DevForce EDM Designer Extension looks for a file named DomainModelTemplate.tt in a
well-known place. DomainModelTemplate.tt is actually a template for making .tt templates. It
has placeholder tokens for model-specific values. It's the file the DevForce Designer
Extension used to create the SimpleNorthwind.edmx.tt file in the model project.
The goal is to replace the existing DomainModelTemplate.tt file with your version so that the
next time DevForce generates a entity classes from a model ... any model ... it creates a .tt file
based on your template file.
DomainModelTemplate.tt is in another directory, the one mentioned in a comment of the .tt
you edited.
TT // Source for this file located at:
// C:\Users\...\AppData\Local\Microsoft\VisualStudio\10.0\Extensions\IdeaBlade, Inc\
// IdeaBlade OM Designer Extension\6.0.5.0\DomainModelTemplate.tt
The actual directory location varies according to machine, operating system, and user name.
Copy the model project .tt file that you just edited into template directory
Backup the current DomainModelTemplate.tt by renaming it (e.g.,
DomainModelTemplate.tt.backup)
Rename your modified .tt file to DomainModelTemplate.tt
Now edit this new version of DomainModelTemplate.tt to put in the placeholder tokens.
Change:
TT // Source for this file located at:
// C:\Users\...\AppData\Local\Microsoft\VisualStudio\10.0\Extensions\IdeaBlade, Inc\
// IdeaBlade OM Designer Extension\6.0.5.0\DomainModelTemplate.tt
// SimpleNorthwind.edmx <--- Needed so "Transform Related Text Templates On Save"
works correctly.
To:
TT // Source for this file located at: $templateFullFileName$
// $edmxname$ <--- Needed so "Transform Related Text Templates On Save" works
correctly.
All future .tt files created for any model project will be based on this new template.
You can also update an older project that was generated with the old template version.
delete its .tt file
make a fake change to the EDMX file (e.g., move an object on the canvas)
save
This triggers recreation of the EDMX's .tt file and regenerates your model using the new
template.
#3 Move your custom generator to its own assembly
This third step builds on the second.
The goal is to be able to edit your custom template generator in Visual Studio so you can take
advantage of Intellisense, type-checking, and Visual Studio debugging.
You will extract your custom MyTemplate class from the template and put it in its own
assembly.
Create a new project. Let's call it MyTemplateAssembly. Then create the MyTemplate
class from the code you wrote earlier.
When adding references, you can find the IdeaBlade.VisualStudio.OM.CodeGenerator assembly in
the DesktopAssemblies folder where DevForce is installed. e.g. C:/Program Files/DevForce
2010/DesktopAssemblies
C#
using IdeaBlade.EntityModel.Edm.Metadata;
using IdeaBlade.VisualStudio.OM.CodeGenerator;

namespace MyTemplateAssembly {
public class MyTemplate : DomainModelTemplate {

public MyTemplate(Microsoft.VisualStudio.TextTemplating.TextTransformation
textTransformation)
: base(textTransformation) {}

protected override void WriteEntityDataPropertyAttributes(EdmPropertyWrapper property) {
WriteAttribute("Foo(" + Quote(property.Name) + ")");
base.WriteEntityDataPropertyAttributes(property);
}
}
}
VB
Imports IdeaBlade.EntityModel.Edm.Metadata
Imports IdeaBlade.VisualStudio.OM.CodeGenerator

Public Class MyTemplate
Inherits DomainModelTemplate
Public Sub New(ByVal textTransformation As _
Microsoft.VisualStudio.TextTemplating.TextTransformation)
MyBase.New(textTransformation)
End Sub

Protected Overrides Sub WriteEntityDataPropertyAttributes( _
ByVal property1 As EdmPropertyWrapper)
WriteAttribute("Foo(" & Quote(property1.Name) & ")")
MyBase.WriteEntityDataPropertyAttributes(property1)
End Sub
End Class
Make a new version of DomainModelTemplate.tt from the original backup copy.
Edit this DomainModelTemplate.tt file to use your custom template generator.
Add a reference to the custom template generator's assembly
Replace usage of the DevForce DomainModelTemplate class with your class.
The final DomainModelTemplate.tt would look something like this:
T4 <#@ template language="C#" debug="true" hostSpecific="true" #>
<#@ output extension="./DontReadMe" #>
<#@ Assembly Name=,path to MyTemplateAssembly- #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="IdeaBlade.VisualStudio.DTE.dll" #>
<#@ Assembly Name="IdeaBlade.VisualStudio.OM.CodeGenerator.dll" #>
<#@ Assembly Name="IdeaBlade.EntityModel.Edm.Metadata.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="IdeaBlade.VisualStudio.DTE" #>
<#@ import namespace="IdeaBlade.VisualStudio.OM.CodeGenerator" #>
<#@ import namespace="IdeaBlade.EntityModel.Edm.Metadata" #>
<#
// Source for this file located at: $templateFullFileName$
// $edmxname$ <--- Needed so "Transform Related Text Templates On Save" works
correctly.
var template = new MyTemplate(this);
template.Generate();
#>
<#+
#>
Notice that you must spell out the full path to your assembly reference: <#@ Assembly
Name={path to MyTemplateAssembly} #>/
You could sign MyTemplateAssembly and install it in the GAC. Then you could refer to it as you do
regular .NET and IdeaBlade assemblies: <#@ Assembly Name=MyTemplateAssembly #>. This might
make it easier to share with other developers on your team.
Congratulations! You're done! Future .tt files created for a model project will be based on
your new template and you'll be able to maintain that template efficiently in Visual Studio.
Customize the model
The generated entity model is typically extended with additional business logic such as
validation rules, UI hints, calculated properties and workflow methods. This topic introduces
some of these customization techniques.


Limits of code generation
The generated entity model classes are the product of the DevForce T4 template (the .tt file)
and the conceptual entity metadata inscribed in the edmx file. The template prescribes how
classes and properties are written. The metadata describe what classes and properties are
written.
The EDM Designer, as extended by DevForce, gives you some control over aspects of the
classes and their properties, in particular their accessibility, UI hints and schema-determined
validation attributes. But you are limited to describing persistent classes and their data and
navigation properties - the values stored in database tables and the pathways to related
entities. There is no place in the EDMX to specify constructors, calculations, events,
workflow methods or validation rules, no way to define classes or properties that aren't
directly translatable to data storage.

You can modify the T4 template (the .tt file) to change how the classes are implemented.
That's not an effective instrument for detailing the semantics of individual entity classes.
When you need the Customer class to be more than a bag of persistent data (CustomerID,
CompanyName, etc.), to have behavior that expresses what it means to be a "customer" in the
application domain, you'll extend the Customer class with handwritten, custom code.
Customize Entities
You don't customize the entity model by modifying the generated code; you'd lose those
changes the next time you ran the code generator.
You cannot extend generated entity classes by subclassing them. Neither DevForce nor Entity
Framework will work with derived entity classes.
Instead you customize by writing code in one or all of three places:
1. A partial class file
2. A metadata class file (the "buddy class")
3. A helper class to which the entity delegates, perhaps for validation or property interception.
Add a partial class file
The DevForce T4 code generator emits a partial classes. You can add capabilities to the
generated entity classes by writing supplemental code in your own partial class files.


You add partial class files to the model project, knowing that the compiler will combine the
class definitions it finds in all source code files when it builds the final entity classes.
All partial class source code files must be in the same project as the generated class files.
To illustrate this technique of extending the generated entity classes, we'll add a Customer
partial class that enhances the generated Customer class.
Begin by adding a new source code file to the same model project calling it Customer.cs (or
Customer.vb). To this file you could add a Customer class that looks like this one:
C#
[DebuggerDisplay("{ToString()}")]
[RequiresAuthentication]
public partial class Customer
{
public Customer()
{
CustomerID = SystemGuid.NewGuid();
}

[Display(Name = "Original", AutoGenerateField = true, Order = 3)]
public bool IsOriginal
{
get { return CustomerID_OLD != String.Empty; }
}

public bool CanDelete { get { return !IsOriginal; }}

// Enforce integrity of order before adding
public void AddOrder(Order order) {/*...*/}

// Enforce rules for removing an order
public void RemoveOrder(Order order) {/*...*/}

// Trim spaces from Company name
[BeforeSet(EntityPropertyNames.CompanyName)]
public void TrimNameBeforeSet(
PropertyInterceptorArgs<Customer, String> args)
{
if (args.Value != null) args.Value = args.Value.Trim();
}

public override string ToString()
{
return String.Format("{0}({1})", CompanyName, CustomerID);
}
}
VB
<DebuggerDisplay("{ToString()}")>
<RequiresAuthentication> _
Partial Public Class Customer
Public Sub New()
CustomerID = SystemGuid.NewGuid()
End Sub

<Display(Name := "Original", AutoGenerateField := True, Order := 3)>
Public ReadOnly Property IsOriginal() As Boolean
Get
Return CustomerID_OLD <> String.Empty
End Get
End Property

Public ReadOnly Property CanDelete() As Boolean
Get
Return Not IsOriginal
End Get
End Property

' Enforce integrity of order before adding
Public Sub AddOrder(ByVal order As Order) '...
End Sub

' Enforce rules for removing an order
Public Sub RemoveOrder(ByVal order As Order) '...
End Sub

' Trim spaces from Company name
<BeforeSet(EntityPropertyNames.CompanyName)>
Public Sub TrimNameBeforeSet(ByVal args As PropertyInterceptorArgs(Of Customer, String))
If args.Value IsNot Nothing Then
args.Value = args.Value.Trim()
End If
End Sub

Public Overrides Function ToString() As String
Return String.Format("{0}({1})", CompanyName, CustomerID)
End Function
End Class
The example demonstrates many of the kinds of customizations you might make such as:
The class-level RequiresAuthentication attribute - one of several security attributes; - ensures
that only authenticated users can query or save Customers.
An explicit default constructor initializes the Guid EntityKey for new customers.
A custom, read-only IsOriginal property that reports if this Customer is one of the original
Northwind customers.
The Display attribute hints to the UI how to label and position the IsOriginal property.
CanDelete, AddOrder and RemoveOrder express workflow and integrity rules.
An attributed property interceptor trims spaces from ends of input CompanyName.
The ToString overrides is especially useful during debugging.
The class-level DebuggerDisplay attribute delivers a friendlier value in the debugger.
Adding constructors
Like any .NET class, the compiler imputes a public default, parameterless constructor unless
you write a constructor of your own. DevForce doesn't generate a constructor. But you can
write one (as shown in the example) and the partial class is a good place to do it.
You might even write a constructor with parameters in which case you must also add a
default, parameterless constructor. Another topic covers writing entity constructors in greater
detail. For now we'll just call out the importance of having a public default constructor.
Link to the Silverlight application
We can't use the .NET entity classes in a Silverlight application. The Silverlight application
has to have its own version of those classes. To ensure the fidelity of definitions in both .NET
and Silverlight environments, the Silverlight model project link to the source code files in the
.NET model project.
DevForce takes care of linking to the generated source code files automatically. The
developer must link to custom source code files manually.
Limits of the partial class
A partial class can add new features but it cannot change existing features of a generated
class. You can't make a public property private. You can't change its implementation either.
But you can "re-attribute" them in a metadata "buddy" class.
Link to source files
This topic describes how to link to .NET model source code files from a Silverlight model
project and why you'd want to do that.


We can't use .NET entity classes in a Silverlight application.
While Silverlight and .NET projects are written in the same .NET languages, they don't share
the same supporting libraries. While they both have libraries with the same names and the
same functions, these are not the same assemblies. Silverlight can't make use of any full .NET
library.
That's why a Silverlight application can't consume the entity classes in your full .NET entity
model.
This fact causes serious pain. When you are responsible for building an entire data-driven,
business application, back to front, from server to Silverlight client, you want one
implementation of each conceptual entity. You don't want two versions: one in Silverlight and
one in full .NET.
Coordinating entity definitions
You could rely on code-generation magic to automatically write and rewrite the sort-of-
similar-but-not-really Silverlight versions of the full .NET entities. This is the approach taken
by WCF RIA Services.
The DevForce takes a different tack. DevForce strives for perfect fidelity between Silverlight
and .NET class definitions by ensuring that the source code is the same source code for
entities compiled on both sides.
That guarantee is made possible by link items in the Silverlight model project that point to
corresponding entity source code files in the .NET model project. Changes to an entity class
file, whether made from within the Silverlight project or from within the .NET project, are
actually changes to the same physical source code file.
When the projects are (re)compiled, both Silverlight and .NET entity classes are built from
the same source code. The resulting classes are as identical as they can be.
Linking
This screenshot shows generated entity class source files in a web application project linked
to the Silverlight application project:

Notice the shortcut symbol on the Silverlight project item name indicating that the item is a
link.

Automatic linking
DevForce will automatically generate a link to your auto-generated model and developer
classes, using the following rules:
1. If only a single Silverlight project is in the solution, it will be the link target.
2. Assembly name "matching" is done: DevForce will look for the first Silverlight project (in
assembly name order) whose assembly name starts with the server project's "root" assembly
name. This "root" name is the server project's assembly name with any trailing "Web" or
".Web" removed. For example, if the server project assembly name is "MyApplication.Web",
DevForce will look for a Silverlight project whose assembly name starts with
"MyApplication".
3. If you've manually created or moved a link DevForce will honor that link and not remove or
modify it.
If a target project can't be found then a message will be written to the output window. You
can still manually create the link, as discussed below.
Manual linking
DevForce takes care of linking the Silverlight project to the .NET generated source code
files.
The developer must manually link the source code files - such as partial class files - that he
creates on his own. You create the link - once - by doing the following:
Select the Silverlight project
Right-mouse-click and select Add | Existing item... (or press Ctrl-Shift-A)
Navigate to the web application project's directory
Scatter select the code files to link (hold down Ctrl key while clicking each file)
Do not click the Add button. To the right of the Add button is a drop-down arrow; click that
to reveal "Add" menu choices

Pick "Add As Link"
The selected files are now linked in the Silverlight application as we see here with Customer
and Department partial class files.

Preserving differences deliberately
Sometimes you have business logic that should only execute on one side or the other.
DevForce makes full type fidelity possible but it doesn't mandate it.
You could use compiler directives within a source code file to include or exclude statements
that only apply in Silverlight or .NET.
A cleaner and easier way is to create additional partial class files, either in the .NET project or
in the Silverlight project, and deliberately not link them.
It's a good idea to give the files special names that announce your intention and prevent
confusion. IdeaBlade uses the ".Desktop" and ".SL" extension conventions for this purpose.
Customer.Desktop and Customer.SL are suggested names for Customer class files containing
code to run only in full .NET or only in Silverlight.
Add a Metadata class
The EntityMetadata class gives you complete control over the attributes that adorn the
generated entity class properties.


Attributes are an increasingly popular means of adding information and behavior to the
members of a class.
Many UI technologies, WPF and Silverlight controls in particular, inspect the data-bound
entity properties, looking for UI hint attributes such as Display. The vocabulary of UI hint
attributes is rich and growing.
Validation engines on both client and server also inspect entities for validation attributes such
as Required; the engines turn these attributes into rules that they apply when validating
entities.
The DevForce code generator adds many such attributes to the generated classes. But it
probably won't get all of the ones that you care about and you may want to impose different
values for some of the attributes DevForce does supply.
The DevForce EDM Designer Extension gives you some control over the generated attributes
but not as much control as you might need. Once the classes have been generated, their
attributes are baked in.
There is no direct way to add unanticipated attributes to the generated property. The code
generator doesn't know about them. Again, once the classes have been generated, their
attributes are baked in.
A property with a problem
For example, here is the CompanyName property generated for the Customer class.
C#
/// <summary>Gets or sets the CompanyName. </summary>
[Bindable(true, BindingDirection.TwoWay)]
[Editable(true)]
[Display(Name="CompanyName", AutoGenerateField=true)]
[IbVal.StringLengthVerifier(MaxValue=40,
IsRequired=true,
ErrorMessageResourceName="Customer_CompanyName")]
[DataMember]
public string CompanyName {
get { return PropertyMetadata.CompanyName.GetValue(this); }
set { PropertyMetadata.CompanyName.SetValue(this, value); }
}
VB
''' <summary>Gets or sets the CompanyName. </summary>
<Bindable(True, BindingDirection.TwoWay), Editable(True), _
Display(Name:="CompanyName", AutoGenerateField:=True), _
IbVal.StringLengthVerifier(MaxValue:=40, IsRequired:=True, _
ErrorMessageResourceName:="Customer_CompanyName"), DataMember>
Public Property CompanyName() As String
Get
Return PropertyMetadata.CompanyName.GetValue(Me)
End Get
Set(ByVal value As String)
PropertyMetadata.CompanyName.SetValue(Me, value)
End Set
End Property
We might prefer a different label than "CompanyName" and want automatic layout controls
to position the name near the front or top.
Write a metadata class
Fortunately, you can write an entity metadata class (aka, the "buddy" class) to specify
precisely the attributes that should be applied to a designated property. You can add any
attribute to a generated property, including custom attributes that you wrote. And you can
remove or replace attributes with the help of the metadata class
The DevForce T4 code generator looks for a metadata class associated with a class it is
generating. If it sees a public field or property name in that buddy class that matches the name
of a property it would generate, it applies the attributes on that buddy class property instead of
the attributes it would otherwise have generated.
C#
[MetadataType(typeof(Customer.CustomerMetadata))]
[DebuggerDisplay("{ToString()}")]
public partial class Customer
{
//...

public static class CustomerMetadata
{
[Display(Name = "ID", AutoGenerateField = true, Order = 0)]
[Editable(false)]
public static Guid CustomerID;

[Display(Name = "Name", AutoGenerateField = true, Order = 1)]
[DoNothingCustom]
public static string CompanyName;

// Country is nullable in database but we want to require it
[RequiredValueVerifier]
public static string Country;

[Bindable(true, BindingDirection.OneWay)]
[Editable(false)]
[Display(Name = "CustomerID_OLD", AutoGenerateField = false)]
public static Guid CustomerID_OLD;
}

}
VB
<MetadataType(GetType(Customer.CustomerMetadata)), _
DebuggerDisplay("{ToString()}")>
Partial Public Class Customer
'...

Public NotInheritable Class CustomerMetadata
<Display(Name := "ID", AutoGenerateField := True, Order := 0), _
Editable(False)>
Public Shared CustomerID As Guid

<Display(Name := "Name", AutoGenerateField := True, Order := 1), _
DoNothingCustom>
Public Shared CompanyName As String

' Country is nullable in database but we want to require it
<RequiredValueVerifier>
Public Shared Country As String

<Bindable(True, BindingDirection.OneWay), Editable(False), _
Display(Name := "CustomerID_OLD", AutoGenerateField := False)>
Public Shared CustomerID_OLD As Guid
End Class

End Class
Some observations:
The MetadataType attribute is essential. It tells DevForce that a buddy class exists and
where to find it.
The metadata class is an inner static class in this example. Itcould stand on its own, perhaps
in a separate code file.
The metadata class is public as are its properties and fields.
The Editable attributes warns the UI not to facilitate changing the key (CustomerID)
The Display attribute specifies the desired label and relative position of the ID field if the UI
will be laying out the view automatically.
CompanyName gets a label change and its own custom attribute, DoNothingCustom. It may
mean nothing to .NET controls but it might mean something to your code.
The Country property is nullable in the database; the RequiredValueVerifier ensures that it
must have a value anyway if the Customer is to be saved.
The attributes on CustomerID_OLD instruct the UI to hide that property and forbid change if
possible.
Re-running the code generator with this metadata class in place causes DevForce to produce
different code for these properties than it would have otherwise. Here's the CompanyName
property for example:
C#
/// <summary>Gets or sets the CompanyName. </summary>
[Display(Name = "Name", AutoGenerateField = true, Order = 1)]
[SimpleNorthwindModel.DoNothingCustom]
[Bindable(true, BindingDirection.TwoWay)]
[Editable(true)]
[IbVal.StringLengthVerifier(MaxValue=40,
IsRequired=true,
ErrorMessageResourceName="Customer_CompanyName")]
[DataMember]
public string CompanyName {
get { return PropertyMetadata.CompanyName.GetValue(this); }
set { PropertyMetadata.CompanyName.SetValue(this, value); }
}
VB
''' <summary>Gets or sets the CompanyName. </summary>
<Display(Name := "Name", AutoGenerateField := True, _
Order := 1), SimpleNorthwindModel.DoNothingCustom, Bindable(True, _
BindingDirection.TwoWay), Editable(True), IbVal.StringLengthVerifier(MaxValue:=40, _
IsRequired:=True, ErrorMessageResourceName:="Customer_CompanyName"), DataMember>
Public Property CompanyName() As String
Get
Return PropertyMetadata.CompanyName.GetValue(Me)
End Get
Set(ByVal value As String)
PropertyMetadata.CompanyName.SetValue(Me, value)
End Set
End Property
See the revised Display and new DoNothingCustom attributes. We didn't touch the validation
attributes so the templated validation remains in place.
DevForce does not re-generate the model automatically after changes to the metadata class.
REMEMBER to re-run the code generation tool after changing the metadata class so that its
attributes are merged into the generated class code.
Link to Silverlight?
In this example, the metadata class is an inner class of the custom Customer class located in a
partial class file.
The Silverlight model project is presumably already linked to this partial class as we
discussed in the partial class topic so there's no additional linking required.
What if we had put the metadata class in a separate class file? Should the Silverlight project
link to it then? It depends.
There's no need if the metadata class file contains nothing but attributes adorning static fields
or properties; DevForce code-generation will have baked their effects into the generated
classes already; the metadata class has served its purpose.
On the other hand, if the metadata class defines other business logic, such as the validation
rules in the Customer class example, then you must link to this metadata class manually in
order to make that logic available on the Silverlight client.
Add custom base class
Generated entity classes ultimately inherit from Entity but you can inject your own custom
entity base class at the root of your entity model's inheritance hierarchy in order to provide
common state and behaviors across the model. This topic explains how.


In many applications there is logic that every entity should share. It's natural to put this logic
in a base class and have all of your entity classes inherit from it.
A wrong way
You happen to know that when an entity class inherits from another class, you specify the
base class in the EDM Designer Base Type property. You consider creating an empty, abstract
EntityBase type in the conceptual model and setting every entity's Base Type property to
"EntityBase".
That won't work for several reasons chief among them: Entity Framework insists that all
entity types be mapped to a store object. There is no store object for EntityBase and you can't
create one either.
Name it in Injected Base Type
The DevForce EDM Designer Extension added many code generation control properties
including a model-level Injected Base Type property. You set the Injected Base Type to
"EntityBase" in the EDM Designer Properties Window as shown:

Base type code-generation
The DevForce code generator substitutes EntityBase wherever it would have specified the
DevForce Entity class.
C# public partial class Customer : EntityBase {...}
VB
Partial Public Class Customer Inherits EntityBase ...
End Class
It also adds to the entity source code file an empty EntityBase partial abstract class that
inherits from Entity:
C#
using IbEm = IdeaBlade.EntityModel;
...
[DataContract(IsReference=true)]
[IbEm.DiscoverableType(IbEm.DiscoverableTypeMode.KnownType)]
public abstract partial class EntityBase : IbEm.Entity {
}
VB
Imports IbEm = IdeaBlade.EntityModel
...
<DataContract(IsReference=True)>
<IbEm.DiscoverableType(IbEm.DiscoverableTypeMode.KnownType)>
Partial Public MustInherit Class EntityBase Inherits IbEm.Entity
EndClass
Add code to EntityBase
Now add the logic that you want all entities to share ... but not to the generated EntityBase
class! Your changes would be lost the next time you re-generated the entity class file ... which
happens often.
Instead, follow the same pattern for extending generated entity classes: add a partial class file
called EntityBase.cs (or EntityBase.vb).
Remember to link to it in your Silverlight model project.
Here's an example with a dummy property:
C#
public partial class EntityBase
{
/// <summary>
/// <see cref="EntityBase"/> demo property that gets the name of the concrete type.
/// </summary>
protected internal string EntityTypeName { get { return This.GetType().Name; } }
}
VB
Partial Public Class EntityBase
''' <summary>
''' <see cref="EntityBase"/> demo property that gets the name of the concrete type.
''' </summary>
Protected Friend ReadOnly Property EntityTypeName As String
Get
Return Me.GetType().Name
End Get
End Property
End Class
Base class in a different assembly
You can define the EntityBase class in a different assembly if you want to share it with
multiple models in multiple projects. You might even use EntityBase in different DevForce
applications.
DevForce has a naming convention for that purpose. If the name supplied to the Injected Base
Type EDM Designer extension property contains a period (.), DevForce assumes that the
named class already exists elsewhere and uses the name exactly as you specified it.
Suppose you defined EntityBase in a class library called Common. Presumably its namespace
is also called Common. Set the I njected Base Typeto "Common.EntityBase". Add a
reference to the Common library to your model project. DevForce will generate entities that
inherit from Common.EntityBase.
Imitate the generated EntityBase if you decide to write your own in a different project.
Remember to inherit from Entity and include the two class-level attributes shown above.
Base class for specific entity classes
Perhaps you want a few of your entity classes to inherit from a special base class dedicated
just to them.
For example, suppose that Customer and Employee have functionality in common as "actors"
in the domain.
These classes have no properties in common and they do not inherit from another entity
model class (i.e., they are not involved in any form of Entity Framework inheritance). For
reasons known only to you they have some business logic in common. That logic is irrelevant
or incorrect for all other model entities so you refuse to put that logic in the model-wide
EntityBase class.
You've already defined an abstract Actor class to hold this logic (see below). Now you want
to make Customer and Employee inherit from Actor.
You'll have to modify the DevForce code generation template to do it. You can't specify a
custom base class for individual entity types in the designer.
You will be tempted by the EDM Base Type property. It won't work. That property is constrained to
other types in the entity model.
Fortunately, it's not difficult.
Follow the steps for customizing the DevForce T4 template
Override the DomainModelTemplate.GetEntityClassDef method as shown below
Set the EDM Tag property of both Customer and Employee to "Actor"; your custom template
will know to use the Actor class when it sees this Tag.

Here is the suggested method override:
C#
protected override ClassDef GetEntityClassDef
(EntityOrComplexTypeWrapper entityOrComplexType) {
String baseName;

var entityType = entityOrComplexType as EntityTypeWrapper;

bool isAbstract;
if (entityType != null) {
baseName = GetMyEntityBaseTypeName(entityType); // <-- substitute
//baseName = GetEntityBaseTypeName(entityType); // <-- original
isAbstract = entityType.IsAbstract;
} else {
baseName = "IbEm.ComplexObject";
isAbstract = false;
}
var classDef = new ClassDef(FmtName(entityOrComplexType.Name),
FmtName(baseName),
entityOrComplexType.Accessibility)
.SetAbstract(isAbstract)
.SetPartial(true);
return classDef;
}

protected static string GetMyEntityBaseTypeName(EntityTypeWrapper entityType) {
if (entityType.Tag.Contains("Actor")) return "Actor"; // ToDo: replace magic string
return GetEntityBaseTypeName(entityType);
}
VB
Protected Overrides Function GetEntityClassDef(ByVal entityOrComplexType As _
EntityOrComplexTypeWrapper) As ClassDef
Dim baseName As String

Dim entityType = TryCast(entityOrComplexType, EntityTypeWrapper)

Dim isAbstract As Boolean
If entityType IsNot Nothing Then
baseName = GetMyEntityBaseTypeName(entityType) ' <-- substitute
'baseName = GetEntityBaseTypeName(entityType); // <-- original
isAbstract = entityType.IsAbstract
Else
baseName = "IbEm.ComplexObject"
isAbstract = False
End If
Dim classDef = New ClassDef(FmtName(entityOrComplexType.Name), FmtName(baseName), _
entityOrComplexType.Accessibility).SetAbstract(isAbstract).SetPartial(True)
Return classDef
End Function

Protected Shared Function GetMyEntityBaseTypeName(ByVal _
entityType As EntityTypeWrapper) As String
If entityType.Tag.Contains("Actor") Then ' ToDo: replace magic string
Return "Actor"
End If
Return GetEntityBaseTypeName(entityType)
End Function
Notice that the GetMyEntityBaseTypeName method checks for the word "Actor" in the Tag
property that DevForce added to the EDM Designer properties. If the Tag contains "Actor"
(as it will for Customer), the method returns the "Actor" base name ... and Customer inherits
from Actor. If it doesn't (as Order does not), the method returns the injected base type name -
"EntityBase" in this case - and Order inherits directly from EntityBase.
The Tag property is a great way to tell your custom code generation method what to do on a
case-by-case basis. It's easy to set from within the EDM Designer.
Important: The Actor class must inherit from the DevForce Entity class. It probably will
inherit from your EntityBase which inherits from Entity.
C#
[DataContract(IsReference = true)]
[IbEm.DiscoverableType(IbEm.DiscoverableTypeMode.KnownType)]
public abstract class Actor : EntityBase { ... }
VB
<DataContract(IsReference = True)>
<IbEm.DiscoverableType(IbEm.DiscoverableTypeMode.KnownType)>
Public MustInherit Class Actor Inherits EntityBase
End Class
Do not insert another entity model class between Actor and Entity. The Entity Framework
demands an unbroken chain of entity inheritance within the model. Customer->Actor-
>BaseEntity->Entity is OK because, once you get to Actor, there are no more entity model
ancestor classes. Customer->Actor->SomeModelEntity->BaseEntity->Entity is not OK.
Specify the null entity
The null entity (informally known as the nullo) is a special version of an entity class that
represents the "entity not found". Every entity class defines its own null entity.
You don't have to do anything to define the null entity. The default properties of the nullo
are adequate for most purposes. But you can change any property value if you don't like the
default by overriding the UpdateNullEntity method in the partial class.
An EntityManager will call this method exactly once when it first needs a nullo of the given
type. In this example, we make the nullo's Customer.CompanyName property return "N/A".
C#
public partial class Customer {
//...

// Custom implementation for NullEntity
protected override void UpdateNullEntity() {
this.CompanyName = "N/A";
}
}
VB
Partial Public Class Customer
'...

' Custom implementation for NullEntity
Protected Overrides Sub UpdateNullEntity()
Me.CompanyName = "N/A"
End Sub
End Class

Property interceptors
Last modified on March 14, 2011 12:57
DevForce provides a mechanism to intercept and either modify or extend the behavior of any
property on a DevForce entity. This property interception is intended to replace, and expand
upon, the technique of marking properties as virtual and overriding them in a subclass. This
facility is a lightweight form of what is termed Aspect-Oriented Programming.
Interception can be accomplished either statically, via attributes on developer-defined
interception methods, or dynamically, via runtime calls to the PropertyInterceptorManager.
Attribute interception is substantially easier to write and should be the default choice in most
cases.

Attribute interception
DevForce provides a mechanism to intercept and either modify or extend the behavior of any
property on a DevForce entity. This attribute interception is intended to replace, and expand
upon, the technique of marking properties as virtual and overriding them in a subclass. This
facility is a lightweight form of what is termed Aspect-Oriented Programming.
Interception can be accomplished either statically, via attributes on developer-defined
interception methods, or dynamically, via runtime calls to the PropertyInterceptorManager.
Attribute interception is substantially easier to write and should be the default choice in most
cases.
DevForce supplies four attributes that are used to specify where and when property
interception should occur. These attributes are:
BeforeGetAttribute
BeforeSetAttribute
AfterGetAttribute
AfterSetAttribute
Under most conditions these attributes will be placed on methods defined in the custom
partial class associated with a particular DevForce entity. For example, the code immediately
below represents a snippet from the auto-generated Employee class.
(Generated code)
C#
public partial class Employee : IdeaBlade.EntityModel.Entity {
public string LastName {
get {
return PropertyMetadata.LastName.GetValue(this);
}
set {
PropertyMetadata.LastName.SetValue(this, value);
}
}
VB
Partial Public Class Employee
Inherits IdeaBlade.EntityModel.Entity
Public Property LastName() As String
Get
Return PropertyMetadata.LastName.GetValue(Me)
End Get

Set(ByVal value As String)
PropertyMetadata.LastName.SetValue(Me, value)
End Set
End Property
Property interception of the get portion of this property would be accomplished by adding the
following code fragment to a custom Employee partial class definition:
C#
[AfterGet(EntityPropertyNames.LastName)]
public void UppercaseNameAfterGet(PropertyInterceptorArgs<Employee, String> args) {
var lastName = args.Value;

if (!String.IsNullOrEmpty(lastName)) {
args.Value = args.Value.ToUpper();
}
}
VB
<AfterGet(EntityPropertyNames.LastName)>
Public Sub UppercaseNameAfterGet(ByVal args As PropertyInterceptorArgs(Of
Employee, String))
Dim lastName = args.Value

If Not String.IsNullOrEmpty(lastName) Then
args.Value = args.Value.ToUpper()
End If
End Sub
DevForce will insure that this method is automatically called as part of any call to the
Employee.LastName get property. The AfterGet attribute specifies that this method will be
called internally as part of the get process after any internal get operations involved in the
get are performed. The effect is that the LastName property will always return an uppercased
result. For the remainder of this document, methods such as this will be termed interceptor
actions.
The corresponding set property can be intercepted in a similar manner.
C#
[BeforeSet(EntityPropertyNames.LastName)]
public void UppercaseNameBeforeSet(IbCore.PropertyInterceptorArgs<Employee,
String> args) {
var name = args.Value;

if (!String.IsNullOrEmpty(name)) {
args.Value = args.Value.ToUpper();
}
}
VB
<BeforeSet(EntityPropertyNames.LastName)> _
Public Sub UppercaseLastName(ByVal args As PropertyInterceptorArgs(Of Employee,
String))
Dim lastName = args.Value

If Not String.IsNullOrEmpty(lastName) Then
args.Value = args.Value.ToUpper()
End If
End Sub
In this case we are ensuring that any strings passed into the LastName property will be
uppercased before being stored in the Employee instance ( and later persisted to the backend
datastore). Note that, in this case, the interception occurs before any internal operation is
performed.
In these two cases we have implemented an AfterGet and a BeforeSet interceptor.
BeforeGet and AfterSet attributes are also provided and operate in a similar manner.
Define an interceptor to act against multiple types
Last modified on March 31, 2011 10:56
You can also define an interceptor to work across more than one type; e.g., against
multiple entity types. In this event, you will want to locate the interceptor in a separate (non-
entity) class; and you will need to tell DevForce explicitly to discover the interceptors therein
in order to activate them.
Heres an AfterGet interceptor that intercepts every Get against every property of the
Employee and Product entities. (Dont overuse this technique, or you may slow down your
app unacceptably!) The interceptor checks to see if the property is a DateTime, or something
derived from a DateTime, and that its value is not null. If both things are true, it converts the
DateTime to local time. (The interceptor assumes that the DateTime has been stored in the
database as a universal time.)
C#
[IbCore.AfterGet(TargetType = typeof(Employee))]
[IbCore.AfterGet(TargetType = typeof(Product))]
public static void UniversalGetInterceptor(IbEm.IEntityPropertyInterceptorArgs args) {
bool isDateTime = args.EntityProperty.DataType.IsAssignableFrom(typeof(DateTime));
bool valueIsNull = args.Value == null;

if (isDateTime && !valueIsNull) {
DateTime aDateTime = ((DateTime)args.Value);
aDateTime = aDateTime.ToLocalTime();
args.Value = aDateTime;
}
}
VB
<IbCore.AfterGet(TargetType:=GetType(Employee)), _
IbCore.AfterGet(TargetType:=GetType(Product))> _
Public Shared Sub UniversalGetInterceptor(ByVal args As IbEm.IEntityPropertyInterceptorArgs)
Dim isDateTime As Boolean = args.EntityProperty.DataType.IsAssignableFrom (GetType(Date))
Dim valueIsNull As Boolean = args.Value Is Nothing

If isDateTime AndAlso (Not valueIsNull) Then
Dim aDateTime As Date = (CDate(args.Value))
aDateTime = aDateTime.ToLocalTime()
args.Value = aDateTime
End If
End Sub
Note that, since we defined the above interceptor in a non-entity class, we had to specify in
the AfterGet attributes the types against which it is to operate: here, Employee and Product.
DevForce wont find interceptors defined outside entity classes automatically. In these cases
you need to tell the PropertyInterceptorManager where to look. Heres how you let DevForce
know youve defined some interceptors in a class named AuxiliaryPropertyInterceptors:
C
#
IbCore.PropertyInterceptorManager.CurrentInstance.DiscoverInterceptorsFromAttributes(typeof(
AuxiliaryPropertyInterceptors));
V
B
IbCore.PropertyInterceptorManager.CurrentInstance.DiscoverInterceptorsFromAttributes(typeof(
AuxiliaryPropertyInterceptors))

Dynamic property interception and the PropertyInterceptorManager
Last modified on March 24, 2011 13:59
The PropertyInterceptorManager is a singleton, available to the developer via its
CurrentInstance property. The current instance is the container for all currently registered
interceptor actions. To directly add actions to the PropertyInterceptorManager, use the
AddAction method. For example:
C#
PropertyInterceptorManager.CurrentInstance.AddAction(
new PropertyInterceptorAction<PropertyInterceptorArgs<Entity,Object>>(
typeof(Entity), null, PropertyInterceptorMode.BeforeSet,
(args) => Debug.WriteLine("Entity BeforeSet"), 0.0, "A")
);
VB
PropertyInterceptorManager.CurrentInstance.AddAction( _
New PropertyInterceptorAction(Of PropertyInterceptorArgs(Of Entity, Object)) _
(GetType(Entity), Nothing, PropertyInterceptorMode.BeforeSet, _
Function(args) Debug.WriteLine("Entity BeforeSet"), 0.0, "A"))

EntityProperties and property interceptors
Last modified on March 24, 2011 12:51
Contents
Within a DevForce entity, every property has a GetterInterceptor and a SetterInterceptor.
These interceptors can be used to add or remove the AddAction actions associated with that
property. Under the covers this is going through the PropertyInterceptorManager mechanism,
but the syntax is often simpler. For example:
C#
Employee.PropertyMetadata.Title.GetterInterceptor.AddAction(
IbCore.PropertyInterceptorTiming.Before,
args => args.Value = args.Value.ToUpper());
VB
Employee.PropertyMetadata.Title.GetterInterceptor.AddAction( _
IbCore.PropertyInterceptorTiming.Before, Function(args) _
args.Value = args.Value.ToUpper())

Interceptor chaining and ordering
Last modified on March 24, 2011 12:52
Any given property may have more than one interceptor action applied to it. For example:
C#
#region Chained Interceptors
[AfterGet(EntityPropertyNames.LastName)]
public void UppercaseLastName(
PropertyInterceptorArgs<Employee, String> args) {
/// do something interesting
}
[AfterGet(EntityPropertyNames.LastName)]
// same mode (afterGet) and property name as above
public void InsureNonEmptyLastName(
PropertyInterceptorArgs<Employee, String> args) {
// do something else interesting
}
[AfterGet] // same mode as above and
//applying to all properties on employee.
public void AfterAnyEmployeeGet(
PropertyInterceptorArgs<Employee, Object> args) {
// global employee action here
}
#endregion Chained Interceptors
VB
<AfterGet(EntityPropertyNames.LastName)> _
Public Sub UppercaseLastName(ByVal args _
As PropertyInterceptorArgs(Of Employee, String))
''' do something interesting
End Sub
<AfterGet(EntityPropertyNames.LastName)> _
Public Sub InsureNonEmptyLastName(ByVal args _
As PropertyInterceptorArgs(Of Employee, String))
' do something else interesting
End Sub
<AfterGet()> _
Public Sub AfterAnyEmployeeGet(ByVal args _
As PropertyInterceptorArgs(Of Employee, Object))
' global employee action here
End Sub
In this case, three different interceptor actions are all registered to occur whenever the
Employee.LastName property is called.
To execute these actions, the DevForce engine forms a chain where each of the registered
interceptor actions is called with the same arguments that were passed to the previous action.
Any interceptor can thus change the interceptor arguments in order to change the input to the
next interceptor action in the chain. The default order in which interceptor actions are called
is defined according to the following rules.
1. Base class interceptor actions before subclass interceptor actions.
2. Named interceptor actions before unnamed interceptor actions.
3. Attribute interceptor actions before dynamic interceptor actions.
4. For attribute interceptor actions, in order of their occurrence in the code.
5. For dynamic interceptor actions, in the order that they were added to the
PropertyInterceptorManager.
Because of the rigidity of these rules, there is also a provision to override the default order
that any interceptor action is called by explicitly setting its Order property. For attribute
interceptors this is accomplished as follows:
C#
[AfterGet(EntityPropertyNames.ContactName, Order=1)]
public void ContactNameAfterGet03(
IbCore.PropertyInterceptorArgs<Customer, String> args) {
...
}
VB
<BeforeSet(EntityPropertyNames.LastName, Order:=-1.0)> _
Public Sub UppercaseLastName(ByVal args As _
PropertyInterceptorArgs(Of Employee, String))
'
End Sub
The Order property is defined as being of type double and is automatically defaulted to a
value of 0.0. Any interceptor action with a property of less that 0.0 will thus occur earlier
than any interceptors without a specified order and any value greater that 0.0 will
correspondingly be called later, and in order of increasing values of the Order parameter.
Exact ordering of interceptor actions can thus be accomplished.

Multiple attributes on a single interceptor action
Last modified on March 24, 2011 12:56
There will be cases where you want a single interceptor action to handle more than one
property but less than an entire class. In this case, it may be useful to write an interceptor
action similar to the following:
C#
[BeforeSet(EntityPropertyNames.FirstName)]
[BeforeSet(EntityPropertyNames.LastName)]
public void UppercaseName(
IbCore.PropertyInterceptorArgs<Employee, String> args) {
var name = args.Value;
if (!String.IsNullOrEmpty(name)) {
args.Value = args.Value.ToUpper();
}
}
VB
<BeforeSet(EntityPropertyNames.FirstName), BeforeSet(EntityPropertyNames.LastName)> _
Public Sub UppercaseName(ByVal args As _
PropertyInterceptorArgs(Of Employee, String))
Dim name = args.Value
If Not String.IsNullOrEmpty(name) Then
args.Value = args.Value.ToUpper()
End If
End Sub

Named vs. unnamed interceptor actions
Last modified on March 24, 2011 12:58
The property interception code snippets in previous topics were all examples of what are
termed Named interceptor actions, in that they each specified a single specific named
property to be intercepted. It is also possible to create Unnamed interceptor actions that
apply to all of the properties for a specific target type. For example, suppose that the
following code were implemented in the Employee partial class:
C#
[BeforeSet]
public void BeforeSetAny(IbCore.IPropertyInterceptorArgs args) {
if (!Thread.CurrentPrincipal.IsInRole("Administrator")) {
throw new InvalidOperationException("Only admistrators can change Product data!");
}
}
VB
<BeforeSet> _
Public Sub BeforeSetAny(ByVal args As IPropertyInterceptorArgs)
If Not Thread.CurrentPrincipal.IsInRole("Administrator") Then
Throw New InvalidOperationException( _
"Only admistrators can change data")
End If
End Sub
The result of this code would be that only those users logged in as administrators would be
allowed to call any property setters within the Employee class.
A similar after set action might look like the following:
C#
[AfterSet]
public void AfterSetAny(IbCore.IPropertyInterceptorArgs args) {
LogChangeToCustomer(args.Instance);
}
VB
<AfterSet> _
Public Sub AfterSetAny(ByVal args As IPropertyInterceptorArgs)
LogChangeToEmployee(args.Instance)
End Sub

This would log any changes to the employee class.
Later in this document we will also describe how to define interceptors that apply across
multiple types as well as multiple properties within a single type.
Property interception mechanics
Last modified on March 24, 2011 13:00
Property interception within DevForce is accomplished by dynamically generating
compiled lamda expressions for each interceptor action. DevForce interceptors are
discovered (but not compiled) as each entity class is first referenced. Runtime compilation of
each property interceptor occurs lazily the first time each property is accessed. After this first
access, the entire code path for each property access is fully compiled. Properties that are
never accessed do not require compilation. The addition or removal of interceptor actions
after they have been compiled does require a new compilation the next time the property is
executed. This happens automatically.
Errors encountered during the compilation process will thus appear when a property is
accessed for the first time. These exceptions will be of type PropertyInterceptorException and
will contain information on the specific method that could not be compiled into a property
interceptor action. These are usually a function of a PropertyInterceptorArgs parameter type
that is not compatible with the property or properties being accessed.
PropertyInterceptor keys
Last modified on March 31, 2011 11:41
Every property interceptor action has a key that can either be specified via an optional
attribute property or dynamically when the action is first created. If no key is defined, the
system will automatically create one. This key will be used to identify an action for removal.
The PropertyInterceptorManager.RemoveAction(interceptorAction) attempts to find an
interceptor that matches the one passed in. This match requires that the TargetType,
TargetName, Mode , and Key be the same between the two interceptor actions.
PropertyInterceptorArgs and IPropertyInterceptorArgs
Interceptor actions get all of the information about the context of what they are intercepting
from the single interceptor argument passed into them. This argument will obviously be
different for different contexts; i.e. a set versus a get action, a change to an employee versus a
company, a change to the FirstName property instead of the LastName property. Because of
this there are many possible implementations of what the single argument passed into any
interceptor action might contain. However, all of these implementations implement a single
primary interface: IPropertyInterceptorArgs.
Every interceptor action shown previously provides an example of this. In each case, a single
argument of type PropertyInterceptorArgs<Employee, String of type
IPropertyInterceptorArgs> was passed into each of the interceptor methods.
In fact, the type of the args instance that is actually be passed into each of these methods at
runtime is an instance of a subtype of the argument type declared in the methods signature.
For any interceptor action defined on a DevForce entity, the actual args passed into the action
will be a concrete implementation of one of the following classes.
DataEntityPropertyGetI nterceptorArgs<TI nstance, TValue>
DataEntityPropertySetInterceptorArgs<TI nstance, TValue>
NavigationEntityPropertyGetI nterceptorArgs<TI nstance, TValue>
NavigationEntityPropertySetI nterceptorArgs<TI nstance, TValue>
The boldfaced characters above indicate whether we are providing interception to a get or a
set property, as well as whether we are intercepting a data or a navigation property.
In general, you can write an interception method with an argument type that is any base class
of the actual argument type defined for that interceptor. If you do use a base class, then you
may need to perform runtime casts in order to access some of the additional properties
provided by the specific subclass passed in at runtime. These subclassed properties will be
discussed later.
The entire inheritance hierarchy for property interceptor arguments is shown below:
Assembly Where Defined Property Interceptor Arguments
IdeaBlade.Core
IPropertyInterceptorArgs
IPropertyInterceptorArgs<TInstance, TValue>
PropertyInterceptorArgs<TInstance, TValue>
IdeaBlade.EntityModel
DataEntityPropertyInterceptorArgs<TInstance, TValue>
DataEntityPropertyGetInterceptorArgs<TInstance, TValue>
DataEntityPropertySetInterceptorArgs<TInstance, TValue>
NavigationEntityPropertyInterceptorArgs<TInstance, TValue>
NavigationEntityPropertyGetInterceptorArgs<TInstance, TValue>
NavigationEntityPropertySetInterceptorArgs<TInstance, TValue>
The generic <TInstance> argument will always be the type that the intercepted method will
operate on, known elsewhere in this document and the interceptor API as the TargetType.
The <TValue> argument will be the type of the property being intercepted. i.e. String for the
LastName property.
Note that the interceptor arguments defined to operate on DevForce entities break into
multiple subclasses with additional associated interfaces based on two primary criteria.
1. Is it a get or a set interceptor?
1. get interceptor args implement IEntityPropertyGetInterceptorArgs
2. set interceptor args implement IEntityPropertySetInterceptorArgs
2. Does it involve a DataEntityProperty or a NavigationEntityProperty?.
1. DataEntityProperty args implement IDataEntityPropertyInterceptorArgs
2. NavigationEntityProperty args implement INavigationEntityPropertyInterceptorArgs
The API for each of the interfaces above is discussed below.
IPropertyInterceptorArgs
The root of all property interceptor arguments is the IPropertyInterceptorArgs interface. Its
properties will be available to all interceptors.
C#
public interface IPropertyInterceptorArgs {
Object Instance { get; }
Object Value { get; set; }
bool Cancel { get; set; }
Action<Exception> ExceptionAction { get; set; }
object Tag { get; set; }
object Context { get; }
}
VB
Public Interface IPropertyInterceptorArgs
ReadOnly Property Instance() As Object
Property Value() As Object
Property Cancel() As Boolean
Property ExceptionAction() As Action(Of Exception)
Property Tag() As Object
ReadOnly Property Context() As Object
End Interface
In general the most useful of these properties will be the Instance and Value properties.
The Instance property will always contain the parent object whose property is being
intercepted. The Value will always be the value that is being either retrieved or set.
The Cancel property allows you to stop the execution of the property interceptor chain at
any point by setting the Cancel property to true.
The ExceptionAction property allows you to set up an action that will be performed
whenever an exception occurs anywhere after this point in the chain of interceptors.
The Tag property is intended as a general purpose grab bag for the developer to use for
his/her own purposes.
The Context property is used for internal purposes and should be ignored.
An example of using the ExceptionAction and Cancel is shown below:
Code Listing 8. Order.LogExceptionsAndCancelSets(). Demoed in
MainDemo.TestLoggingOfExceptionsAndAutoCancellationOfSets().
C#
/// Do not let any setters throw an exception. Instead, eat them,
/// log them, and cancel the remainder of the Set operation.
[IbCore.BeforeSet(Order = -1)]
public void LogExceptionsAndCancelSets(
IbCore.IPropertyInterceptorArgs args) {
args.ExceptionAction = (e) => {
Common.LogManager.LogAnAction(string.Format(
"Here in {0}", e.Message));
args.Cancel = true;
};
}
VB
''' <remarks>
''' Do not let any setters throw an exception. Instead, eat them,
''' log them, and cancel the remainder of the Set operation.
''' </remarks>
<IbCore.BeforeSet(Order:=-1)> _
Public Sub LogExceptionsAndCancelSets(ByVal args _
As IbCore.IPropertyInterceptorArgs)
args.ExceptionAction = Sub(e)
Common.LogManager.LogAnAction( _
String.Format("Here in: {0}", e.Message))
args.Cancel = True
End Sub
End Sub
Note that we applied an explicit Order value less than 0 for this interceptor. Assuming that
none of the property-specific interceptors have an explicit Order defined, their Order value
defaults to zero, this interceptor will run first for all properties of the type on which its
defined.
In our samples, this interceptor happens to be defined on the Order type. Please note
that there is no relationship between that fact and the use of the Order parameter in the
BeforeSet attribute. Two different things!
Generic IPropertyInterceptorArgs
The following is a generic version of IPropertyInterceptorArgs where both the Instance and
Value properties are now strongly typed; otherwise it is identical to IPropertyInterceptorArgs.
C#
public interface IPropertyInterceptorArgs<TInstance, TValue> :
IdeaBlade.Core.IPropertyInterceptorArgs {
TInstance Instance { get; }
TValue Value { get; set; }
bool Cancel { get; set; }
Action<Exception> ExceptionAction { get; set; }
object Tag { get; set; }
object Context { get; }
}
VB
Public Interface IPropertyInterceptorArgs(Of TInstance, TValue)
Inherits IdeaBlade.Core.IPropertyInterceptorArgs
ReadOnly Property Instance() As TInstance
Property Value() As TValue
Property Cancel() As Boolean
Property ExceptionAction() As Action(Of Exception)
Property Tag() As Object
ReadOnly Property Context() As Object
End Interface
IEntity PropertyInterceptorArgs and subclasses
Whereas the interfaces above can be used to intercept any property on any object, the
argument interfaces below are for use only with DevForce specific entities and complex
objects. Each interface below provides additional contextual data to any interceptor actions
defined to operate on DevForce entities.
The most basic of these is simply the idea that each property on a DevForce entity has a
corresponding EntityProperty ( discussed elsewhere in this guide).
C#
public interface IEntityPropertyInterceptorArgs :
IbCore.IPropertyInterceptorArgs {
IbEm.EntityProperty EntityProperty { get; }
}
VB
Public Interface IEntityPropertyInterceptorArgs
Inherits IbCore.IPropertyInterceptorArgs
ReadOnly Property EntityProperty() As IbEm.EntityProperty
End Interface
An example is shown below:
Code Listing 9. Customer.AfterSetAnyUsingIEntityPropertyInterceptorArgs().
C#
[IbCore.AfterSet]
public void AfterSetAnyUsingIEntityPropertyInterceptorArgs(
IbCore.IPropertyInterceptorArgs args) {
// Cast the IPropertyInterceptorArgs to the entity-specific version, then
// values information available on the EntityProperty contained thereby.
var entityPropertyArgs = args as IbEm.IEntityPropertyInterceptorArgs;
if (entityPropertyArgs != null) {
Common.LogManager.LogAnAction(string.Format(
"Property [Customer.{0}] was set to the value: [{1}]",
entityPropertyArgs.EntityProperty.Name, args.Value.ToString()));
}
}
VB
<AfterSet()> _
Public Sub AfterSetAny(ByVal args As IPropertyInterceptorArgs)
Dim entityPropertyArgs = TryCast(args, IEntityPropertyInterceptorArgs)
If entityPropertyArgs IsNot Nothing Then
Log("The " + entityPropertyArgs.EntityProperty.Name + _
" was set to the value:= " + args.Value.ToString())
End If
End Sub
The next two interfaces provide additional context based on whether the interceptor action
being performed is a get operation or a set operation.
For a get operation, IdeaBlade entities have a concept of possibly multiple versions, i.e. an
original, current, or proposed version, of an entity at any single point in time. It may be useful
to know which version is being retrieved during the current action. Note that the version
cannot be changed.
C#
public interface IEntityPropertyGetInterceptorArgs :
IEntityPropertyInterceptorArgs {
IbEm.EntityVersion EntityVersion { get; }
}
VB
Public Interface IEntityPropertyGetInterceptorArgs
Inherits IEntityPropertyInterceptorArgs
ReadOnly Property EntityVersion() As IbEm.EntityVersion
End Interface
The DevForce EntityProperty is an abstract class with two concrete subclasses; a
DataEntityProperty and a NavigationEntityProperty ( discussed elsewhere in this guide). The
next two IEntityPropertyInterceptorArgs subinterfaces allow access to instances of one or the
other of these depending on whether the property being intercepted is a data or a navigation
property.
C#
public interface IDataEntityPropertyInterceptorArgs :
IEntityPropertyInterceptorArgs {
IbEm.DataEntityProperty DataEntityProperty { get; }
}
VB
Public Interface IDataEntityPropertyInterceptorArgs
Inherits IEntityPropertyInterceptorArgs
ReadOnly Property DataEntityProperty() As _
IbEm.DataEntityProperty
End Interface
C#
public interface INavigationEntityPropertyInterceptorArgs :
IEntityPropertyInterceptorArgs {
IbEm.NavigationEntityProperty NavigationEntityProperty { get; }
}
VB
Public Interface INavigationEntityPropertyInterceptorArgs
Inherits IEntityPropertyInterceptorArgs
ReadOnly Property NavigationEntityProperty() As _
IbEm.NavigationEntityProperty
End Interface
IPropertyInterceptorArgs Type Coercion
One of the first issues that a developer will encounter with writing interceptor actions that
handle more than one property is that it becomes difficult or impossible to use a concrete
subtype as the argument to the interceptor.
For example, imagine that we wanted to write a single action that handled two or more very
different properties each of a different type:
This could be written as follows:
Code Listing 10. Employee.ActionToBePerformedAgainstDifferentTypesV1().
C#
[BeforeSet(EntityPropertyNames.HireDate)] // hire date is of type datetime
[BeforeSet(EntityPropertyNames.FirstName)] // firstname is of type string
public void ActionToBePerformedAgainstDifferentTypesV1(
IbCore.IPropertyInterceptorArgs args) {
var emp = (Employee)args.Instance;
var entityProperty = ((IbEm.IDataEntityPropertyInterceptorArgs)
args).EntityProperty;
//.. do some action with emp and entityProperty
}
VB
' hire date is of type datetime
' firstname is of type string
<IbCore.BeforeSet(EntityPropertyNames.HireDate)> _
<IbCore.BeforeSet(EntityPropertyNames.FirstName)> _
Public Sub ActionToBePerformedAgainstDifferentTypesV1(ByVal args As _
IbCore.IPropertyInterceptorArgs)
Dim emp = DirectCast(args.Instance, Employee)
Dim entityProperty = DirectCast(args, _
IbEm.IDataEntityPropertyInterceptorArgs).EntityProperty
'.. do some action with emp and entityProperty
End Sub
But ideally we would prefer to write it like this, in order to avoid performing a lot of
superfluous casts:
Code Listing 11. Employee.ActionToBePerformedAgainstDifferentTypesV2().
C#
[IbCore.BeforeSet(EntityPropertyNames.HireDate)]
// hire date is of type datetime
[IbCore.BeforeSet(EntityPropertyNames.FirstName)]
// firstname is of type string
public void ActionToBePerformedAgainstDifferentTypesV2(
IbEm.DataEntityPropertySetInterceptorArgs<Employee, Object> args) {
// no casting
var emp = args.Instance;
var entityProperty = args.DataEntityProperty;
//.. do some action with emp and entityProperty
}
VB
' hire date is of type datetime
' firstname is of type string
<IbCore.BeforeSet(EntityPropertyNames.HireDate)> _
<IbCore.BeforeSet(EntityPropertyNames.FirstName)> _
Public Sub ActionToBePerformedAgainstDifferentTypesV2( _
ByVal args As IbEm.DataEntityPropertySetInterceptorArgs( _
Of Employee, [Object]))
' no casting
Dim emp = args.Instance
Dim entityProperty = args.DataEntityProperty
'.. do some action with emp and entityProperty
End Sub
The problem is that, according to the rules of inheritance, the two concrete classes that this
method will be called with:
Type 1: DataEntityPropertySetInterceptorArgs<Employee, String>
Type 2: DataEntityPropertySetInterceptorArgs<Employee, DateTime>
do not inherit from:
Type 3: DataEntityPropertySetInterceptorArgs<Employee, Object>
In fact, the only class or interface that they do share is:
IPropertyInterceptorArgs
So in order to allow this construction, DevForce needs to coerce each of Type1 and
Type2 into Type3 for the duration of the method call.
Because DevForce does do this, any of the following arguments are also valid:
Type 4: DataEntityPropertySetInterceptorArgs<Entity, Object>
Type 5: DataEntityPropertySetInterceptorArgs<Object, Object>
Type 5: PropertyInterceptorArgs<Employee, Object>
etc.
The basic rule for the type coercion facility is that any concrete type can be specified if its
generic version is a subtype of the generic version of the actual argument type that will be
passed in.

The EntityPropertyNames class
Last modified on March 31, 2011 14:37
In all of the previous examples we have shown Named attributes specified with the form
EntityPropertyNames.{PropertyName}. This is a recommended pattern that ensures type
safety. However, the following two attribute specifications have exactly the same effect:
C#
[BeforeSet(EntityPropertyNames.FirstName)]

// or

[BeforeSet("FirstName")]
VB
<BeforeSet(EntityPropertyNames.FirstName)>

' or

<BeforeSet("FirstName")>
The EntityPropertyNames reference is to a class that is generated (as multiple partial
classes) inside the designer code file associated with the EntityModel. Its primary purpose is
to allow specification of property names as constants. Note that because EntityPropertyNames
is generated as a set of partial classes, you can add your own property names to the class for
any custom properties that you create.

Interception method signatures
While the property interceptor methods described previously allow a great deal of control
over the entire interception process, there are times when this is overkill. Sometimes all you
really want is to do is modify or inspect the incoming or outgoing values. In these cases, a
simplified signature for an interception method is also provided.
Standard interceptor action
Code Listing 14. Employee.UppercaseLastName().
C#
[IbCore.AfterGet(Employee.EntityPropertyNames.LastName)]
public void UppercaseLastName(
IbCore.PropertyInterceptorArgs<Employee, String> args) {
var lastName = args.Value;
if (!String.IsNullOrEmpty(lastName)) {
args.Value = args.Value.ToUpper();
}
}
VB
<IbCore.AfterGet(Employee.EntityPropertyNames.LastName)>
Public Sub UppercaseLastName(ByVal args As _
IbCore.PropertyInterceptorArgs(Of Employee, String))
Dim lastName = args.Value
If Not String.IsNullOrEmpty(lastName) Then
args.Value = args.Value.ToUpper()
End If
End Sub
Alternative interceptor action
Code Listing 15. Employee.UppercaseLastNameV2().
C#
[IbCore.AfterGet(Employee.EntityPropertyNames.LastName)]
public String UppercaseLastNameV2(String lastName) {
if (!String.IsNullOrEmpty(lastName)) {
return lastName.ToUpper();
} else {
return String.Empty;
}
}
VB
<IbCore.AfterGet(Employee.EntityPropertyNames.LastName)>
Public Function UppercaseLastNameV2(ByVal lastName As String) As String
If Not String.IsNullOrEmpty(lastName) Then
Return lastName.ToUpper()
Else
Return String.Empty
End If
End Function
In general, any property interceptor action that only inspects or modifies the incoming value
without the need for any other context can be written in this form. In fact, if the action does
not actually modify the incoming value, the return type of the interceptor action can be
declared as void.

PropertyInterceptor attribute discovery
Last modified on March 31, 2011 15:03
In general, any interceptor method declared within a DevForce entity and marked with a
property interceptor attribute will be automatically discovered before the first property
access. PropertyInterceptors will most commonly be defined within the developer-controlled
partial class associated with each entity.
Property interceptors can also be defined on any base class and these will also be discovered
automatically.
In order to reduce the surface area of any entity class, a developer may not want to expose the
property interceptor methods directly on the surface of his or her class. To facilitate this,
DevForce will also probe any public inner classes of any entity class and will locate any
property interceptors defined there as well.
Example:
C#
/// </summary>
/// <remarks>
/// Property interceptors will also be discovered inside internal class
/// of the Entity class.
/// </remarks>
public class PropertyInterceptorsDefinitions {
[IbCore.BeforeGet(Employee.EntityPropertyNames.LastName)]
public static void LastNameInterceptor
(IbEm.IEntityPropertyInterceptorArgs args) {
// ...
}
[IbCore.AfterSet]
public static void LoggingInterceptor
(IbEm.IEntityPropertyInterceptorArgs args) {
// ...
}
}
VB
Public Class PropertyInterceptorsDefinitions
<IbCore.BeforeGet(Employee.EntityPropertyNames.LastName)> _
Public Shared Sub LastNameInterceptor(ByVal args _
As IbEm.IEntityPropertyInterceptorArgs)
' ...
End Sub
<IbCore.AfterSet()> _
Public Shared Sub LoggingInterceptor(ByVal args _
As IbEm.IEntityPropertyInterceptorArgs)
' ...
End Sub
End Class
Important note: Property interceptor methods defined on a class directly may be
either instance or static methods; whereas property interceptors defined on an inner
class (or anywhere other than directly on the entity class) must be static methods.
In the event that a developer wants to completely isolate his interception methods in another
non-entity-based class, then discovery will not occur automatically. In this case, the
DiscoverInterceptorsFromAttributes method on the PropertyInterceptorManager class may
be used to force discovery of any specified type and all of its base types.
Attribute interceptors that are declared outside of the classes to which they apply must be
further qualified via the TargetType property as shown below:
C#
[IbCore.AfterSet(Employee.EntityPropertyNames.LastName,
TargetType = typeof(Employee))]
public static void LoggingInterceptor(
IbEm.IEntityPropertyInterceptorArgs args) {
// ...
}
VB
Public Class UnattachedInterceptor
<IbCore.AfterSet(Employee.EntityPropertyNames.LastName, _
TargetType:=GetType(Employee))>
Public Shared Sub LoggingInterceptor(ByVal args _
As IbEm.IEntityPropertyInterceptorArgs)
' ...
End Sub
End Class
Examine model metadata
Last modified on April 04, 2011 10:08
Contents
The EntityMetadataStore
Property Metadata
Examine entity model metadata programmatically by interrogating the EntityMetadata
object held in the EntityMetadataStore singleton.


The EntityMetadataStore
DevForce maintains a thread-safe repository of metadata for all types in a domain model.
Applications can query the store using the GetEntityMetadata() method for a type:
C#
EntityMetadata employeeEntityMetaData =
EntityMetadataStore.Instance.GetEntityMetadata(
typeof(DomainModel.Employee));
VB
Dim employeeEntityMetaData As EntityMetadata = _
EntityMetadataStore.Instance.GetEntityMetadata( _
GetType(DomainModel.Employee))
You can also access the EntityMetadata for any entity instance using its EntityAspect:
C#
var cust = _em1.Customers.First();
var metadata = cust.EntityAspect.EntityMetadata;
VB
Dim cust = _em1.Customers.First()
Dim metadata = cust.EntityAspect.EntityMetadata
The EntityMetadata provides the following members:

The table below provides an explanation for a few key members:
Property CanQueryByEntityKey Gets whether primary key queries are allowed.
Property ComplexTypeProperties Returns a collection of DataEntityProperties that describe
complex object properties for entities of this type.
Property ConcurrencyProperties Returns a collection of DataEntityProperties that are
concurrency properties for entities of this type.
Method CreateEntity() Creates a new entity of the type described by this metadata
item.
Property DataProperties Returns a collection of DataEntityProperties for entities of this
type.
Property DataSourceKeyName Gets the name of the Data Source Key associated with this type.
Property DefaultValueFunction Static - Use to override how DevForce sets the default value for
a data entity property.
Property EntityProperties Returns a collection of EntityProperties that belong to entities of
this type.
Property EntityType Gets the type of the entity.
Property ForeignKeyProperties Returns a collection of ForegnKey DataEntityProperties
Property HasStoreGeneratedId Returns whether this entity type has a store generated id.
Property IsComplexObjectType Returns whether this metadata describes a ComplexObject.
Property KeyProperties Returns a collection of DataEntityProperties that are keys for
entities of this type.
Property NavigationProperties Returns a collection of NavigationEntityProperties for entities of
this type.
Property Metadata
When DevForce generates the code for your domain model it includes a nested class called
PropertyMetadata within each generated Entity. Within PropertyMetadata are static fields
for all the EntityProperty definitions within the entity. Youll see a DataEntityProperty for
every non-navigation property, and either a NavigationScalarEntityProperty or
NavigationListEntityProperty for all navigation properties.
You can easily access these properties at any time via the static field definitions:
C#
var dataProp = Customer.PropertyMetadata.Id;
var navListProp = Customer.PropertyMetadata.OrderSummaries;
var navScalarProp = OrderSummary.PropertyMetadata.Customer;
VB
Dim dataProp = Customer.PropertyMetadata.Id
Dim navListProp = Customer.PropertyMetadata.OrderSummaries
Dim navScalarProp = OrderSummary.PropertyMetadata.Customer
Also generated into each Entity class is a nested class called EntityPropertyNames. This
class contains string constants for all the property names within the entity.
C#
public partial class Employee : IbEm.Entity {
public new partial class EntityPropertyNames :
IbEm.Entity.EntityPropertyNames {
public const String Id = "Id";
public const String LastName = "LastName";
public const String FirstName = "FirstName";
}
}
VB
Partial Public Class Employee
Inherits IbEm.Entity
Partial Public Shadows Class EntityPropertyNames
Inherits IbEm.Entity.EntityPropertyNames
Public Const Id As String = "Id"
Public Const LastName As String = "LastName"
Public Const FirstName As String = "FirstName"
End Class
End Class

XML serialization of entities
Last modified on March 25, 2011 15:46
Entities can be serialized into an XML stream or file for any number of purposes, including
exposing these entities from a Web Service, or as the first step in an XSLT transform for
reporting or further processing.
All entities in the code generated by the Entity Data Model Designer are marked with the
DataContract attribute, and all entity properties with the DataMember attribute. These
attributes define how an entity will be serialized by a serializer. They are also required by
DevForce in an n-tier application to query and save entities across tiers.
Serialization using the DataContractSerializer and NetDataContractSerializer is supported.
Serialization using the JSON serializer is not supported because the generated DataContract
attributes for entities set IsReference to true to preserve object references.
Depth of the object graph
One issue when serializing an object graph (objects that are connected to other objects, ad-
infinitum) has to do with the depth of the object graph that should be serialized. Navigation
properties on entities in DevForce are lazily loaded, so you might at first worry that
serialization of a single entity could accidentally cause a large object graph to be
serialized. Fortunately, DevForce controls this by only serializing entities that are present
within the EntityManager's cache at the start of serialization. No queries will be sent to the
data source to load navigation properties not yet loaded, so only the data you want will be
serialized.
For example, if you load an Employee and her Orders into the EntityManager cache and then
serialize the Employee object, the result will also include the loaded Orders. If LineItems for
the Orders had also been loaded into cache, then the object graph serialized would include
them too.
Alternately, if only an Employee was in cache without any attached Orders, then only the
Employee object would be serialized.

The EntityCacheState
Some applications may find the built-in EntityCacheState an easy means of serializing and
deserializing entities. The EntityCacheState is a serializable snapshot of the EntityManager's
cache, or of a selected subset of entities. The EntityCacheState can be serialized in text or
binary format, and can be transmitted across tiers via a remote server method.
Separate the model project
The tutorials instruct you to add your entity model to one of the projects generated from a
DevForce template.
They do so because they are tutorials. The entity model tends to be in its own
project/assembly in production applications. This topic demonstrates how to break out the
entity model into its own assembly.


The Silverlight and WPF tutorials encourage you to add your entity model to one of the
existing projects: the Web Application project in Silverlight examples; the lone application
project in the 2-tier WPF example.
As your application evolves and begins to add other projects that need to reference the entity
model, you may wish you had put the entity model in its own project. You don't have to start
over; it's pretty easy to extract it as its own project and re-link the projects that depend upon
it.
Here you will find step-by-step instructions for Silverlight and non-Silverlight applications.
The Silverlight case is the primary scenario as it requires attention to the linking between full
.NET and Silverlight assemblies. You can follow along with the zip file attached to this page
which contains both "before" and "after" C# Silverlight solutions.
Be sure to backup the entire solution before you begin.
Add a Model project
The new entity model project is a full .NET class library.
Starting in Visual Studio 2010:
From the menu: File | Add | New Project...
Select the Class Library template
Ensure the top-left ComboBox says ".NET Framework 4"
Name it to match the entity model's namespace; we'll call ours "DomainModel"
Delete Class1
In the multi-tier scenarios, the entity model tends to be defined in the web application project;
this is always true for Silverlight and also for n-tier WPF demonstrations.
The directions are the essentially same for a single-project, 2-tier application wherein the entity
model is defined within the lone application project. Follow the instructions here, moving the model
out of that project as one would move it from the web application project.
Move the Entity Framework model (.edmx), the .tt file, and all custom model classes into
DomainModel
Select each model-file (you can do all at once with ctrl-mouse-click)
Drag them to DomainModel
Delete these files from the web application project ( reminder: back-up the solution first )
Add a DomainModel project reference to the web application project
Delete model file links in the Silverlight application project
This section only applies to Silverlight applications built using DevForce 6.0.9 and
earlier.
The links to your entity model are now broken and likely display the yellow warning triangle
icon.
Remove all links to the entity model class files (
Delete the now empty Shared Code folder (if you had one)
You must delete those links before proceeding.
Finish the Model project
You should have a .tt file and a DevForce code-generated file under that .tt file.
You probably also have a code-generated file appears under the .edmx file, that's the Entity
Framework getting involved when it should not.
Open the "Properties" window for the .edmx file by typing Alt-Enter
Notice that the "Custom Tool" entry says EntityModelCodeGenerator.
o Clear the "Custom Tool" entry (it should be empty).
o The Entity Framework generated code file disappears
Right-mouse-click the .tt file
Pick "Run Custom Tool"
This regenerates the code file under the DomainModel namespace and adds the minimally
required references at the same time:
IdeaBlade.Core
IdeaBlade.EntityModel
IdeaBlade.Validation
.NET's System.ComponentModel.DataAnnotations
Make sure you moved over all of the custom model files that you wrote (e.g., custom entity
class files and metadata files).
Fix Model namespace references
The re-located, re-generated entity model classes are now defined in the default namespace
for the model project, DomainModel. That is typically what you want.
It also means that your model namespace references elsewhere are stranded under the old
name. You have to clean them up.
Start with the custom classes you moved into the DomainModel project. A Customer partial
class, for example, is still defined under its old namespace. Use search-and-replace to swap in
the new namespace for all of the custom classes in this project only.
Do not search-and-replace the namespace in other projects, especially not your
application project. The old namespace name remains legitimate for non-model classes. You
are likely to succeed simply by adding "using DomainModel;" statements to the class files
that need them. Let the compiler be your guide. Be patient for now.
How to postpone namespace update
You can postpone this exercise by resetting the default namespace for the DomainModel
project to the old namespace name as it was before we moved these files. That namespace is
probably the default namespace of the Web Application project.
Open the properties editor for the DomainModel project
On the "Application" tab, set the "Default namespace" to the previous model namespace
value
Close that tab
Right-mouse-click the .tt file
Pick "Run Custom Tool"
The entity class file is re-generated again, restoring the entity classes to their old namespace.
You can come back and fix this later. The longer you wait, the more you'll have to clean up.
Build the Model project
Build the DomainModel project. It should build cleanly or be easy to fix as it has no
dependencies on other projects in your solution.
You may need to add one more DevForce library if you are referencing it in any custom class.
IdeaBlade.Linq (only if needed)
Select that reference and open its "Properties Window"
Set the "Specific Version" to False
If this is a non-Silverlight application, you're almost done. Skip ahead to the "Finish the Non-
Silverlight Application" section.
Add a Silverlight Model project
This section applies only to Silverlight applications. Non-Silverlight applications simply
reference the DomainModel project.
In this topic, our assumption is that you want a separate Silverlight application project to
parallel the separate full .NET DomainModel project we just created.
From the menu: File | Add | New Project...
Select the Silverlight Class Library template
Name it to match the entity model's namespace with a .SL suffix; we'll call ours
"DomainModel.SL"
o Choose the "Silverlight 4" version if asked.
Delete Class1
Press Alt-Enter on the new project to open its Properties
On the "Silverlight" tab set the "Default namespace:" to DomainModel (i.e., remove the ".SL"
suffix.
Now you're ready to link to the entity model class files in the DomainModel project.
Press Alt-Shift-A to launch the "Add Existing Item" dialog
Navigate to the DomainModel project that holds the full .NET model files
Select every file code file (.cs or .vb); do not select any other file type.
Do not click the "Add" button
Drop down the ComboBox next to the "Add" button and pick "Add As Link".

Add Silverlight assembly references:
Add DevForce references
o IdeaBlade.Core
o IdeaBlade.EntityModel
o IdeaBlade.Validation
o IdeaBlade.Linq (if needed)
Select all of them and open the "Properties Window"
Set their "Specific Version" to False
Add .NET references
o System.ComponentModel.DataAnnotations
o System.Runtime.Serialization
Build the DomainModel.SL project. It should build cleanly or be easy to fix as it has no
dependencies on other projects in your solution.
Finish the Silverlight Application
Almost there!
Add a reference to the DomainModel.SL project.
Build the entire solution, correcting as necessary.
Run.
The most likely compile errors will be missing references to your re-factored model project.
The entity classes have a new namespace. Adding some "using DomainModel;" statements to
the class files that need them should do the trick.
Finish the Non-Silverlight Application
Almost there!
Add a reference to the DomainModel project.
Build the entire solution, correcting as necessary.
Run.
The most likely compile errors will be missing references to your re-factored model project.
The entity classes have a new namespace. Adding some "using DomainModel;" statements to
the class files that need them should do the trick.




























Query using LINQ
The most common and flexible method of composing a query is to use LINQ syntax with the
EntityQuery.


DevForce LINQ is a comprehensive implementation with unique capabilities:
can execute synchronously and asynchronously.
applies to remote data source, local cache, or both simultaneously.
works in 2-tier mode when the client has line-of-sight access to the database or in n-tier
mode when a remote server mediates between clients and the database.
can be composed statically inline with other code or dynamically to accommodate user-
defined query criteria that can only be known at runtime.
Every valid EntityFramework LINQ query is also a valid DevForce LINQ query. The range
and power of DevForce LINQ querying may best be appreciated by taking a tour of the
EntityFramework's MSDN "101 LINQ Samples" web page. Every sample works in
DevForce, 2-tier or n-tier, whether sent to the database or applied to local cache.
Every EntityFramework entity type can be queried with DevForce LINQ: all forms of
inheritance, complex types, anonymous types, all association cardinalities (including many-
to-many).
The DevForce LINQ query story begins with EntityQuery.
The EntityQuery
DevForce provides the EntityQuery<T> class to support LINQ syntax. The EntityQuery<T>
implements .NET's IQueryable<T> interface and offers a complete implementation of LINQ
functionality, including multiple overloads for all of the following standard LINQ operators:
All, Any, Average, Cast, Concat, Contains, Count, DefaultIfEmpty, Distinct, ElementAt,
Except, First, FirstOrDefault, GroupBy, Join, Last, LastOrDefault, OfType, OrderBy,
OrderByDescending, Select, SelectMany, Single, SingleOrDefault, Skip, SkipWhile, Take,
TakeWhile, ThenBy, ThenByDescending, Sum, Union and Where.
Because an EntityQuery is most commonly used to query an Entity Data Model, DevForce is
subject to the same restrictions which the Entity Framework places on such queries. For more
information, see Supported and Unsupported LINQ Methods (LINQ to Entities).
Note that while an EntityQuery may be restricted from running against the Entity Framework
on the backend, the same query can always be executed locally against the EntityManager's
cache regardless of any backend restrictions. Similarly, POCO queries, are also not subject to
these restrictions. This is why some of the operators listed above, such as ElementAt, Last,
SkipWhile, and TakeWhile, among others, are still provided, even though they cannot be
handled by the Entity Framework. In practice, these restrictions tend to be a minimal
hindrance because there is usually another method or overload that can accomplish the same
result.
Several additional DevForce-specific operators are offered as well, such as FirstOrNullEntity
and support for building untyped LINQ queries dynamically.
EntityQuery basics
Entity queries, like all LINQ queries, can be composed, executed and enumerated in a variety
of stepwise ways. Consider, for example, the following query:
C#
var customersQuery =
from cust in manager.Customers
where cust.ContactTitle == "Sales Representative"
orderby cust.CompanyName
select cust;
VB
Dim customersQuery =
From cust In manager.Customers
Where cust.ContactTitle = "Sales Representative"
Order By cust.CompanyName
Select cust
The same query can also be written using LINQ method-based syntax as shown below:
C#
var customersQuery = manager.Customers
.Where(c => c.ContactTitle == "Sales Representative")
.OrderBy(c => c.CompanyName)
VB
Dim customersQuery = manager.Customers _
.Where(Function(c) c.ContactTitle = "Sales Representative") _
.OrderBy(Function(c) c.CompanyName)
Whether to use query or method syntax is your choice. Both syntaxes provide the same
functionality, with minor differences. We generally use method, sometimes called fluent,
syntax in our samples and snippets, but that's because it's the syntax we're most comfortable
with. If you're a VB developer, query syntax can be much easier to write and read.
The above returns an EntityQuery<Customer>. It's often easier when working with generic
types (especially nested generic types), to use an implicitly typed variable, such as shown
above. This isn't required, and you can still use explicit type variables too.
Creating a query
You may have wondered in looking at the above samples what manager.Customers referred
to, and why you could append LINQ methods to it. When DevForce generates the code for
your entity model it includes these helper properties on the EntityManager. Here's what
Customers looks like:
C#
public IbEm.EntityQuery<Customer> Customers {
get { return new IbEm.EntityQuery<Customer>("Customers", this); }
}
VB
Public ReadOnly Property Customers() As IbEm.EntityQuery(Of Customer)
Get
return new IbEm.EntityQuery(Of Customer)("Customers", Me)
End Get
End Property
DevForce does this to make it easy to compose more complex LINQ queries without having
to explicitly construct the EntityQuery from scratch every time. You're not limited to using
these helper properties, but most developers find them useful.
Basic tasks
The customersQuery we showed above may look a bit daunting if you're new to
LINQ. Queries can be as simple or complex as you need. Here are a few more samples of
simple common queries.
Get all entities of a type
When you need to retrieve all instances of a type, all Employees for example, you need only
provide a simple EntityQuery without restriction or selection methods:
C# var query = manager.Employees;
VB Dim query = manager.Employees
Or in query syntax:
C#
var query = from emp in manager.Employees
select emp;
VB
Dim query = From emp In manager.Employees
Select emp
You can execute the query in any of the ways described below. Remember that if there are
potentially many instances of the type it's usually not a good idea to bring all of them into the
entity cache. If you have 10,000 products for example, you rarely need them all loaded into
memory.
Simple property filter
You'll often want to retrieve a subset of entities based on filter criteria applied to simple
properties of the entity.
For example, a query to retrieve all customers in the UK:
C#
var ukQuery = from cust in manager.Customers
where cust.Country == "UK"
select cust;
VB
Dim ukQuery = From cust In manager.Customers
Where cust.Country = "UK"
Select cust
Query execution
As mentioned earlier, the DevForce EntityQuery<T> implements the IQueryable interface,
which means that the execution of the query is deferred until one of the following operations
is performed on the query
ToList is called on the query.
The query is enumerated in a foreach statement.
One of the EntityManager ExecuteQuery or ExecuteQueryAsync method overloads is called
for the query.
An immediate execution method is called on the query. These methods include First, Single,
Count along with several others.
The AsScalarAsync() method is called followed by a call to an immediate execution method.
Note that Silverlight applications, because of their asynchronous nature, can only make use of
two of these mechanisms:
Calling one of the ExecuteQueryAsync method overloads.
Calling the AsScalarAsync() method on the query followed by a call to an immediate
execution method.
In the example below the addition of a call to ToList() forces DevForce to execute the query
immediately:
C#
List<Customer> customersList = manager.Customers
.Where(c => c.ContactTitle == "Sales Representative")
.OrderBy(c => c.CompanyName)
.ToList();
VB
Dim customersList As List(Of Customer) = manager.Customers _
.Where(Function(c) c.ContactTitle = "Sales Representative") _
.OrderBy(Function(c) c.CompanyName) _
.ToList()
As does the FirstOrNullEntity call in the example below.
C#
Customer firstCustomer = manager.Customers
.Where(c => c.ContactTitle == "Sales Representative")
.OrderBy(c => c.CompanyName)
.FirstOrNullEntity();
VB
Dim firstCustomer As Customer = manager.Customers _
.Where(Function(c) c.ContactTitle = "Sales Representative") _
.OrderBy(Function(c) c.CompanyName) _
.FirstOrNullEntity()
The same queries executed asynchronously, as would be required in Silverlight, would look
like this.
C#
var query = manager.Customers
.Where(c => c.ContactTitle == "Sales Representative")
.OrderBy(c => c.CompanyName);

query.ExecuteAsync(op => {
IEnumerable<Customer> customers = op.Results;
});
VB
Dim query = manager.Customers _
.Where(Function(c) c.ContactTitle = "Sales Representative") _
.OrderBy(Function(c) c.CompanyName)

query.ExecuteAsync(
Sub(op As EntityQueryOperation(Of Customer))
Dim customers As IEnumerable(Of Customer) = op.Results
End Sub)
and
C#
var query = manager.Customers
.Where(c => c.ContactTitle == "Sales Representative")
.OrderBy(c => c.CompanyName);

query.AsScalarAsync().FirstOrNullEntity(op => {
Customer cust = op.Result;
});
VB
Dim query = manager.Customers _
.Where(Function(c) c.ContactTitle = "Sales Representative") _
.OrderBy(Function(c) c.CompanyName)

query.AsScalarAsync().FirstOrNullEntity(
Sub(op As EntityScalarQueryOperation(Of Customer))
Dim cust As Customer = op.Result
End Sub)
In the above you may have noticed that instead of calling either the ExecuteQuery or
ExecuteQueryAsync methods on the EntityManager, we called execute methods directly on
the query itself. Query extension methods such as Execute and ExecuteAsync give you
additional flexibility in how you execute a query. These are usually equivalent to the
EntityManager methods, except with one important distinction. If a query is created without
an EntityManager and executed with a query extension method, then that query will use the
DefaultManager.
You can find more information on asynchronous queries here.
Logging & debugging
The DevForce debug log can be used to see more information regarding which queries are
executed and when. Information about every query sent to the EntityServer will be written to
the debug log. You can also log the generated SQL for queries using the
shouldLogSqlQueries attribute on the logging element in your config file.
Return part of an entity
One common issue when working with entities is how to return part of an entity when only
some of the properties of an entity or collection of entities are needed.


Returning part of an entity, or a "slice", can be useful if an entity type has many properties,
some of which are large (e.g, BLOBS), and a query could return too much data or take too
long to load. Perhaps you are presenting a list of such entities. You won't edit them. If you do
edit them, you will use the list as a reference for identifying entities to edit (e.g., by user
selection); then you will launch a separate editor and load it with the full entity version
retrieved from the database expressly for this purpose.
Slice projections are appropriate in such high volume, "read-only" scenarios where the
savings are measurable and significant. In most cases, though, entities should still be the
primary tool for building any application that requires the update of a domain model's data.
There are two ways to select only part of an entity - using anonymous projections, and
projections into a custom type. We'll describe both below.
Anonymous projections
DevForce supports all of the standard LINQ mechanisms for projection of an anonymous type
from any query. For example, in the snippet below we build a LINQ query that projects out
three properties from the Employee entity type:
C#
var query = manager.Employees
.Select(emp => new { emp.EmployeeID, emp.FirstName, emp.LastName });
VB
Dim query = manager.Employees _
.Select(Function(emp) New With { emp.EmployeeID, emp.FirstName, emp.LastName })

Let's look at query syntax too, since it's easier to use in VB:
C#
var query = from emp in manager.Employees
select new {emp.EmployeeID, emp.FirstName, emp.LastName};
VB
Dim query = From emp In manager.Employees
Select New With {emp.EmployeeID, emp.FirstName, emp.LastName}
When the query is executed, an IEnumerable of anonymous types is returned. Here's where
implicit type names come in handy, since the anonymous type is not statically defined:
C#
var anonItems = query.ToList();
foreach (var anonItem in anonItems) {
int id = anonItem.EmployeeID;
String fName = anonItem.FirstName;
String lName = anonItem.LastName;
}
VB
Dim anonItems = query.ToList()
For Each anonItem In anonItems
Dim id As Integer = anonItem.EmployeeID
Dim fName As String = anonItem.FirstName
Dim lName As String = anonItem.LastName
Next anonItem
It's worth pointing out that anonymous projection queries can be sent to the EntityServer, like
any other query type.
We can issue synchronous or asynchronous queries with anonymous projections too.
C#
query.ExecuteAsync(op => {
foreach (var anonItem in op.Results) {
int id = anonItem.EmployeeID;
String fName = anonItem.FirstName;
String lName = anonItem.LastName;
}
});
VB
query.ExecuteAsync(Sub(op)
For Each anonItem In op.Results
Dim id As Integer = anonItem.EmployeeID
Dim fName As String = anonItem.FirstName
Dim lName As String = anonItem.LastName
Next anonItem
End Sub)
We can also do aggregates and calculations within the projections. For example:
C#
var query = manager.Customers
.Select(c => new { c.CustomerID, TotalFreightWithDiscount = c.Orders.Sum(os => os.Freight *
.85m) });
VB
Dim query = manager.Customers _
.Select(Function(c) New With {Key c.CustomerID, Key .TotalFreightWithDiscount = _
c.Orders.Sum(Function(os) os.Freight *.85D)})
Grouping operations are also supported, as shown in the asynchronous example below.
C#
var query = manager.Customers
.Where(c => c.CompanyName.StartsWith("C"))
.GroupBy(c => c.Country)
.Select(g => new { Country = g.Key, Count = g.Count() });
query.ExecuteAsync(op => {
foreach (var item in op.Results) {
string country = item.Country;
int count = item.Count;
}
});
VB
Dim query = manager.Customers.Where(Function(c) c.CompanyName.StartsWith("C")) _
.GroupBy(Function(c) c.Country).Select(Function(g) New With _
{Key .Country = g.Key, Key .Count = g.Count()})
query.ExecuteAsync(Sub(op)
For Each item In op.Results
Dim country As String = item.Country
Dim count As Integer = item.Count
Next item
End Sub)
You can also select related entities and lists. This is useful too if a filter needs to be applied to
the related entities.
C#
var anonItems = manager.Customers.Select(c => new { c.CompanyName, c.OrderSummaries
}).ToList();
VB
Dim anonItems = manager.Customers.Select(Function(c) New With { c.CompanyName,
c.OrderSummaries }).ToList()
Anonymous types are not public types
Notice that the anonymous type returned by these queries is not public. Anonymous types
have internal (Friend in VB) visibility.
Because of this visibility, you can't directly bind to an anonymous type in
Silverlight. Fortunately, DevForce offers the DynamicTypeConverter helper class that can
convert a non-public anonymous query result into a public type suitable for binding.
C#
var anonItems = manager.Customers.Select(c => new { c.CompanyName, c.OrderSummaries
}).ToList();
var bindableResult = IdeaBlade.Core.DynamicTypeConverter.Convert(anonItems);
VB
Dim anonItems = manager.Customers.Select(Function(c) New With _
{Key c.CompanyName, Key c.OrderSummaries}).ToList()
Dim bindableResult = IdeaBlade.Core.DynamicTypeConverter.Convert(anonItems)
DevForce also offers a helper method which allows you to test whether a query returned an
anonymous type, AnonymousFns.IsAnonymousType .
Limitations
The "slice" projection described here returns an anonymous type, not an entity. The returned
object will not enter the entity cache. The EntityManager does not "remember" the query and
will send the query to the server every time (assuming that a server visit is consistent with the
query strategy and the present state of the EntityManager itself).
Remember that the projected result is not an entity. Even if you could make changes, you
couldn't save those changes ... not in the way you would save entities.
You will also be responsible for coordinating projected values with changes to the source
entities. When you display a list of Employees and change one of them, the displayed
employee list updates to reflect those changes. Change "Nancy" to "Sally" and it changes in
the list too. Not so if the list contains projected employee data - which is disconcerting to
users. You can coordinate with the list yourself at the cost of added complexity, maintenance,
and testing.
Finally, the anonymous types returned by slice projections are difficult to work with.
You can't edit the anonymous result.
You can't bind directly to the anonymous type (without the assistance of the
DyanmicTypeConverter).
In Silverlight you can't access type members outside the assembly.
You may want to transfer the result into a locally defined type to make it easier to work
with. If you expect the projection to have long term, widespread use, you should consider
"table splitting" - an Entity Framework modeling technique which defines two (or more
entities) mapped to the same table. Or you may prefer to define a serializable type that
matches the expected shape and define your projection directly into that, which we'll describe
next.
Project into a custom type
Instead of projecting part of an entity into an anonymous type you have the option of
projecting into a custom type which you've defined. This option can be useful since it
alleviates the difficulties in working with anonymous types. It does, however, require
additional setup.
You must first define the custom type. It must be serializable, a known type, and available on
both client and server. Here's a simple example, using the Employee slice we used above.
C#
[DataContract]
public class EmployeeSlice : IKnownType {

// Employee properties
[DataMember]
public int EmployeeID { get; set; }
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
[DataMember]
public int OrderCount { get; set; }

// Calculated property
public string FullName { get { return FirstName + " " + LastName; } }
}
VB
<DataContract>
Public Class EmployeeSlice
Implements IKnownType

' Employee properties
<DataMember>
Public Property EmployeeID() As Integer
<DataMember>
Public Property FirstName() As String
<DataMember>
Public Property LastName() As String
<DataMember>
Public Property OrderCount() As Integer

' Calculated property
Public ReadOnly Property FullName() As String
Get
Return FirstName & " " & LastName
End Get
End Property
End Class
Note the markup with the DataContract and DataMember attributes - these allow instances of
this class to be moved between client and server tiers. Next note the implementation of the
DevForce marker interface IKnownType. DevForce probes for this interface during its
discovery of known types, and this ensures that DevForce is "aware" that the type may be
used in queries. Also note that the data member properties are public. This isn't strictly
required, but avoids serialization issues. In Silverlight applications you can define internal
setters with a bit of extra work.
You'll want to define this class on both client and server. Why? Because your query will be
created on the client and executed on the server. Both sides must know about it. How do you
define the class on both tiers? The easiest approach, and the one DevForce uses with the
generated entity model, is to create the class file in a "server-side" project and link to the file
(or files) from the "client-side" project. If the project assembly will be deployed to both tiers,
then linking the files is of course not necessary, but you will need to ensure the assembly is
deployed to both tiers.
You'll also want to ensure the class can be discovered by DevForce. If you've modified the
discovery options, be sure that the assembly containing this type will be included.
The query is only slightly different than the anonymous projection query. The "Select" clause
features a "new" keyword followed by our receiving type, "EmployeeSlice". The projection
is no longer anonymous.
C#
var query = manager.Employees
.Select(emp => new EmployeeSlice {
EmployeeID = emp.EmployeeID,
FirstName = emp.FirstName,
LastName = emp.LastName,
OrderCount = emp.Orders.Count(),
});
VB
Dim query = manager.Employees _
.Select(Function(emp) New EmployeeSlice With {
.EmployeeID = emp.EmployeeID,
.FirstName = emp.FirstName,
.LastName = emp.LastName,
.OrderCount = emp.Orders.Count()
})
Use with POCO types
Although we are projecting into a known type, that type is not an entity. The query is not
delivering entities. The result objects do not enter the entity cache. The EntityManager does
not remember the query and will re-send it to the server with every execution unless otherwise
barred from doing so. And you cannot save instances of this type to the database.
If you must store this data in the entity cache you can work around these limitations by
assigning a Key attribute to one or more properties of the type. If instances of the type have a
unique identity then they will be stored in the entity cache when queried, and can be
manipulated and saved as POCO types. The query itself won't be placed in the query cache.
Include related entities
An EntityManager query always returns entities of a single type, the return type identified in
the query object. But what about related entities within the same query such as entities
related to the returned entities? When do we get those? In general, the answer is that you do
not get any related entities until you actually need them. The queries that are executed to
retrieve these entities are called "lazy queries". However, it is often very useful, both for
simplicity of code as well as for performance reasons, to "prefetch" or "eagerly load" data that
you do not immediately need, but that you have a good reason to believe will be needed very
soon. These are called "eager queries".


Eager queries and the Include method
Eager queries are performed using the Include method. The idea behind this method is that
after a query is performed, you sometimes want to retrieve many of the entities directly
related to the entities being returned. You can accomplish this by specifying the "property
paths" to these entities from the returned entities.
For example:
C#
var query = anEntityManager.Customers.Where(c
=>c.CompanyName.StartsWith{"A")).Include("Orders");
VB
Dim query = anEntityManager.Customers.Where(c
=>c.CompanyName.StartsWith{"A")).Include("Orders")
In this case, the "property path" between Customers and Orders was very simple; the
Customer type has an Orders property and it is the name of this property that we are using in
the Include method call. This query will return all of the customers with company names
starting with "A" and will also preload the EntityManager's cache with all of their related
orders.
More complex includes are also possible:
C#
var query = anEntityManager.Customers
.Where(c =>c.CompanyName.StartsWith{"A"))
.Include("Orders.OrderDetails.Product")
.Include("Orders.SalesRep")
VB
Dim query = anEntityManager.Customers _
.Where(c =>c.CompanyName.StartsWith{"A")) _
.Include("Orders.OrderDetails.Product") _
.Include("Orders.SalesRep")
In this case, the Order type has an "OrderDetails" property and a "SalesRep" property, and the
OrderDetail type has a "Product" property.
Note that the property paths may not be valid navigation paths. i.e. you couldn't actually execute
anOrder.OrderDetails.Product because the OrderDetails property returns a collection and it is the
instances of this collection and not the collection itself that has a Product property.
In the preceding examples we have added the Include methods to the end of the query chain,
but we would get exactly the same results if we were to rewrite the query as follows:
C#
var query = anEntityManager.Customers
.Include("Orders.OrderDetails.Product")
.Include("Orders.SalesRep")
.Where(c =>c.CompanyName.StartsWith{"A"))
VB
Dim query = anEntityManager.Customers _
.Include("Orders.OrderDetails.Product") _
.Include("Orders.SalesRep") _
.Where(c =>c.CompanyName.StartsWith{"A"))
Important points
Includes always operate on the 'final' result type of a query, regardless of where they appear
in the query chain.
When using an Include like "Orders.OrderDetails.Product" with multiple "parts" to the
property path, each of the intermediate results will also be added to the EntityManager's
entity cache.
Note that the use of the Include method doesnt change the list of entities returned from the
query. The caller still receives the same results with or without the use of an Include method.
The difference is that before returning these results, the "Include" processing fetches the
related entities and merges them into the cache. This occurs behind the scenes and does not
effect the query result.
When using an Include such as "Orders" for a Customer, the Include retrieves all orders of
each selected Customer. You cannot filter the "Included" orders. If you need to do that,
consider a projection query.
Includes in Silverlight
In Silverlight apps, where all data retrieval must be asynchronous, the benefits of preloading
data ("eager querying") are even more general. In the following snippet, we preload, using
Include method calls, a large object graph a group of Customers that meet a specified
condition. Having done so, all of our subsequent queries for entities can be cache-only and
synchronous:
C#
public void PreloadCustomerOrderData() {
IEntityQuery<Customer> query = anEntityManager.Customers.Where(c => c.Country ==
"France")
.Include("Orders.OrderDetails.Product.Supplier")
.Include("Orders.SalesRep");
_em1.ExecuteQueryAsync(query, GotCustomers);
}

private void GotCustomers(EntityQueryOperation<Customer> args) {
// all of the following queries can now execute synchronously and will return the 'related' entities
from the query above.
var customers = anEntityManager.Customers.With(QueryStrategy.CacheOnly).ToList();
var employees = anEntityManager.Employees.With(QueryStrategy.CacheOnly).ToList();
var orders = anEntityManager.Orders.With(QueryStrategy.CacheOnly).ToList();
var orderDetails = anEntityManager.OrderDetails.With(QueryStrategy.CacheOnly).ToList();
var products = anEntityManager.Products.With(QueryStrategy.CacheOnly).ToList();
var suppliers = anEntityManager.Suppliers.With(QueryStrategy.CacheOnly).ToList();
}
VB
Public Sub PreloadCustomerOrderData()
Dim query As IEntityQuery(Of Customer) = anEntityManager.Customers.Where(Function(c)
c.Country = "France") _
.Include("Orders.OrderDetails.Product.Supplier") _
.Include("Orders.SalesRep")
_em1.ExecuteQueryAsync(query, AddressOf GotCustomers)
End Sub

Private Sub GotCustomers(ByVal args As EntityQueryOperation(Of Customer))
' all of the following queries can now execute synchronously and
' will return the 'related' entities from the query above.
Dim customers = anEntityManager.Customers.With(QueryStrategy.CacheOnly).ToList()
Dim employees = anEntityManager.Employees.With(QueryStrategy.CacheOnly).ToList()
Dim orders = anEntityManager.Orders.With(QueryStrategy.CacheOnly).ToList()
Dim orderDetails = anEntityManager.OrderDetails.With(QueryStrategy.CacheOnly).ToList()
Dim products = anEntityManager.Products.With(QueryStrategy.CacheOnly).ToList()
Dim suppliers = anEntityManager.Suppliers.With(QueryStrategy.CacheOnly).ToList()
End Sub
Performance details
While use of the Include syntax greatly reduces the number of queries submitted to
EntityServer, it is also likely to change the number of queries performed by the backend
database.
This is because a single query with an Include will typically perform one or two database
queries depending on the complexity of the query, but the same query without an include
would result in an initial single query followed by many additional queries spaced out over
time as each individual client side property navigation from the resulting entities caused a
further "lazy" query evaluation. Each of these "lazy evaluations" necessitates a separate trip to
both the EntityServer and then to the database.
In an n-tier deployment using the EntityServer, these "lazy evaluations" can end up being very
expensive because of the latency of the network.
But be careful! You could be trying to get too much data at one time. You could be joining
data from too many tables at one time. Consequently, the query might perform more poorly
than if you had made several trips. Or it might just collapse of its own weight. Make sure you
test your queries.
"Eager queries" are great, but we have also seen them being badly misused. The preceding
paragraphs have enumerated the advantages, but there is sometimes a tendency to think that
because you might need some related entities that you should always "preload" them. This
can be a bad idea if most of the time this data is not needed, and you are still paying the cost
of retrieving and transmitting them.
Performance matters ... but not all time and effort spent optimizing performance returns equal
results. We strongly advise instrumenting your queries during development and testing to
identify performance hotspots. Then optimize where it really matters.
Strongly-typed Includes
Because the Include syntax uses strings that represent "property paths", it is possible that
these paths may be incorrect and that the problem is not discovered until runtime. A type-safe
alternative exists that can be used for all "simple" property paths. A "simple property path" is
one that can be expressed by a simple lambda expression, so "Order.OrderDetails" is a simple
property path but "Order.OrderDetails.Product" is not. The type-safe alternative is to use the
PathFor method that is generated into every DevForce entity type.
C#
var query1 = anEntityManager.Customers
.Where(c =>c.CompanyName.StartsWith{"A"))
.Include(Customer.PathFor( c => c.Orders)); // instead of .Include("Orders");

var query2 = anEntityManager.OrderDetails
.Include(OrderDetail.PathFor( od => od.Product.Suppliers)); // instead of "Product.Suppliers"
VB
Dim query1 = anEntityManager.Customers.Where(Function(c) _
c.CompanyName.StartsWith{"A")).Include(Customer.PathFor(Function(c) c.Orders)) _
' instead of.Include("Orders");

Dim query2 = anEntityManager.OrderDetails.Include(OrderDetail. _
PathFor(Function(od) od.Product.Suppliers)) ' instead of "Product.Suppliers"
The advantage of this syntax is that if any of these property names ever change, the compiler
will catch the error instead of allowing the code to compile with a "bad" include.
Include and filter related entities
A common request is to be able to perform an Include operation where the Include is
modified by a where clause. While this is not currently possible, there is another approach that
accomplishes almost the same thing. The trick is to to use an anonymous projection.


The workaround

Let say we wanted to write a query that looked something like the following. Note that this
code will NOT compile.
C#
var query = anEntityManager.Products.Where(p =>p.Category.Name == "Books")
.(Include("OrderDetails").Where(od => od.Quantity > 5))
VB
Dim query = anEntityManager.Products.Where(Function(p) p.Category.Name = "Books") _
.(Include("OrderDetails").Where(Function(od) od.Quantity > 5))
What we are try to do is select only those Products that are books, and then only Include those
OrderDetails, for these books, where the OrderDetail's Quantity is greater than 5.
The syntax above does NOT work, but we can do something very similar, like this:
C#
var query = anEntityManager.Products.Where(p => p.Category.Name == "Books")
.Select(p => new { Product = p, OrderDetails = p.OrderDetails.Where(od => od.Quantity > 5)
});
var results = query.ToList();
var products = results.Select( x => x.Product);
VB
Dim query = anEntityManager.Products.Where(Function(p) p.Category.Name = _
"Books").Select(Function(p) New With {Key .Product = p, Key .OrderDetails = _
p.OrderDetails.Where(Function(od) od.Quantity > 5)})
Dim results = query.ToList()
Dim products = results.Select(Function(x) x.Product)
The idea here is in DevForce any query that returns entities causes those entities to be added
to the EntityManager's entity cache. This is basically, what the Include extension method does
as well. It bring entities down and "includes" them in the cache, but they are not part of the
"result" of the query.
In the example above we actually return an anonymous type that "includes" both Products
and OrderDetails, so both types of entities are added to the cache. But we don't necessarily
want an anonymous result, what we possibly want is just the list of Products. Hence, the line
after the ToList() call in the example above. In that line we project out just the "Products"
that we just queried.
Paging queries
Last modified on March 29, 2011 17:06
Paging a query in DevForce is performed via the use of the LINQ Take and Skip operators.
For example, if we think of a page size as being 50 entities, then we can fetch any page n of
Customers, using the following kind of query logic.
C#
var pageNumber = 1;
var pageSize = 50;
var pagedQuery = _em1.Customers.Skip((pageNumber-1)*pageSize).Take(pageSize);

var customersOnFirstPage = pagedQuery.ToList();

pageNumber++
var customersOnNextPage = pagedQuery.ToList();

pageNumber = 17;
var customersOnPage17 = pagedQuery.ToList();
VB
Dim pageNumber = 1
Dim pageSize = 50
Dim pagedQuery = _em1.Customers.Skip((pageNumber - 1) * pageSize).Take(pageSize)

Dim customersOnFirstPage = pagedQuery.ToList()

pageNumber = pageNumber + 1
Dim customersOnNextPage = pagedQuery.ToList()

pageNumber = 17
Dim customersOnPage17 = pagedQuery.ToList()
For Silverlight display purposes DevForce provides a class known as the
EntityQueryPagedCollectionView that internally does something very similar. A code sample
is available.
Pass parameters to a query
Last modified on March 23, 2011 22:44
Contents
Closures
We often want to create a query where we can pass parameters to a query to control some
aspect of the query. For database developers there is often a temptation to look for a query
parameters collection on the query to accomplish this task. While such a collection does exist,
it is ONLY intended for use with a very specific subset of POCO queries. In all other cases,
including most POCO query use cases, the alternative provided below is both simpler and
more easily understood.
Closures
Parameters can be easily simulated by using .NET closures. This is simply a complicated way
of saying that we can just include a reference to a local variable in our query and the query
will use the value of this variable when the query is executed. For example, in the query
below, we create a single query object but change the parameter customerName between
executions of this query.
C#
String customerName = null; // The customerName variable is a 'parameter'
var query = myEntityManager.Customers.Where(c =>
c.CompanyName.StartsWith(customerName));
customerName = "ABC";
var customersStartingWithABC = query.ToList();
customerName = "XYZ";
var customersStartingWithXYZ = query.ToList();
VB
Dim customerName As String = Nothing ' The customerName variable is a 'parameter'
Dim query = myEntityManager.Customers.Where(Function(c)
c.CompanyName.StartsWith(customerName))
customerName = "ABC"
Dim customersStartingWithABC = query.ToList()
customerName = "XYZ"
Dim customersStartingWithXYZ = query.ToList()
Basically a variable can be used anywhere a constant value would normally be used in a
query. The value of the variable will be evaluated when the query is executed, not when the
query is composed. Another example is shown below:
C#
float minDiscount = 0;
var query2 = _em1.OrderSummaries.Where(o => o.OrderDetails.Any(od => od.Discount >
minDiscount));
minDiscount = 0.0F;
var ordersWithAnyDiscount = query2.ToList();
minDiscount = 0.1F;
var ordersWithLargeDiscount = query2.ToList();
VB
Dim minDiscount As Single = 0
Dim query2 = _em1.OrderSummaries.Where(Function(o) _
o.OrderDetails.Any(Function(od) od.Discount > minDiscount))
minDiscount = 0.0F
Dim ordersWithAnyDiscount = query2.ToList()
minDiscount = 0.1F
Dim ordersWithLargeDiscount = query2.ToList()
More complex queries that are composed completely dynamically are discussed in dynamic
queries.
One interesting side note here is that the QueryCache, will contain the "resolved" version of
the query. This means that if the same query is executed twice with two different values
provided for any closure "parameters"; two entries will be made in the query cache. For
example, the following two queries will be treated identically by the EntityManager.
C#
customerName = "ABC";
var query1 = myEntityManager.Customers.Where(c =>
c.CompanyName.StartsWith(customerName));
var customersStartingWithABC = query1.ToList();

var query2 = myEntityManager.Customers.Where(c => c.CompanyName.StartsWith("ABC"));
var sameCustomersFromSameQuery = query2.ToList();
VB
customerName = "ABC"
Dim query1 = myEntityManager.Customers.Where(Function(c) _
c.CompanyName.StartsWith(customerName))
Dim customersStartingWithABC = query1.ToList()

Dim query2 = myEntityManager.Customers.Where(Function(c) _
c.CompanyName.StartsWith("ABC"))
Dim sameCustomersFromSameQuery = query2.ToList()





Execute scalar query asynchronously
Last modified on April 24, 2011 17:21
Contents
The problem
AsScalarAsync
A scalar immediate execution query is a LINQ query which performs an aggregation (such as
Count or Group) or returns only one element (such as First or Single). Because these
methods force immediate execution of the query they can't be directly used with
asynchronous queries, but using the AsScalarAsync method you can execute scalar
immediate execution queries asynchronously.


The problem
You've probably noticed something about a query like the following:
C# int ct = manager.Customers.Count();

It doesn't return a query object (an EntityQuery<T>) as other queries do. Instead, it returns the count
of the items in the entity set.
Or consider another example:
C# Customer cust = manager.Customers.First();

It too doesn't return a query, but instead the first customer.
Both these queries are immediate execution queries in LINQ. They differ from the usual
deferred execution queries which allow you to build a query in one step and execute the query
at a later time. Immediate execution queries execute, well, immediately, and synchronously;
you can't separate the creation of the query from the execution.
In an asynchronous environment such as Silverlight, where all queries sent to the EntityServer
must be executed asynchronously, immediate execution queries pose a problem. For
example, you can't do the following:
C#
// Will not work!
var query = manager.Customers.First();
query.ExecuteAsync();
AsScalarAsync
Enter the DevForce AsScalarAsync operator and the EntityScalarAsyncExtensions . It's
easiest to understand this with an example.
C#
var op = manager.Customers.AsScalarAsync().Count();
op.Completed += (o, e) => {
int ct = e.Result;
};

This looks much the same as our earlier synchronous example, with two important differences. One,
AsScalarAsync is called to convert the query to an IEntityScalarQuery<T> before the Count method is
called. Second, an EntityScalarQueryOperation<T> operation object is returned. The query has been
executed immediately, but asynchronously. As with any asynchronous query you can provide a
callback or listen on its Completed event.
Like their synchronous counterparts, these methods can also accept a predicate. For example,
C#
var op = manager.Employees.AsScalarAsync().First(e => e.LastName.StartsWith("D"));
op.Completed += (o, e) => {
Employee emp = e.Result;
};
You can also write more complex queries, such as the one below using an Include:
C#
var op = manager.Employees.Include("Orders").AsScalarAsync().FirstOrNullEntity(e => e.Id == 1);
op.Completed += (o, e) => {
Employee emp = e.Result;
var orders = emp.Orders; // Will not be pending.
};
Here's a query built dynamically:
C#
var query = EntityQuery.Create(typeof(Customer));
var pd = PredicateBuilder.Make("CompanyName", FilterOperator.StartsWith, "D");
var op = query.Where(pd).AsScalarAsync().First();
op.Completed += (o, e) => {
var cust = e.Result;
};
The supported immediate execution methods are: All, Any, Average, Contains, Count, First,
FirstOrDefault, FirstOrNullEntity, LongCount, Max, Min, Single, SingleOrDefault,
SingleOrNullEntity, and Sum. Examples of each are provided in the API documentation .

LINQ query examples
Last modified on May 20, 2011 17:38
Our LINQ query examples contain a collection of sample DevForce LINQ queries organized
according to the type of operator being demonstrated. These samples are based on the
Microsoft Entity Framework Query Samples, which were in turn based on the MSDN "101
LINQ Samples".
You'll find all these samples, and more, in the Query Explorer utility, which will allow you to
download the code and database to explore LINQ at your own pace.
The following pages contain snippets from many of the samples in the Query Explorer to
briefly show query topics by operation.
Restriction operators - Where, Any, All
Examples of the LINQ Where, Any and All operators are shown below. In the
examples below _em1 is an EntityManager.
C#
[Description("This sample uses WHERE to find all customers whose contact title is Sales
Representative.")]
public void LinqToEntities01() {

var query = from cust in _em1.Customers
where cust.ContactTitle == "Sales Representative"
orderby cust.CompanyName
select cust;
var r = query.ToList();
Assert.IsTrue(r.First().CompanyName == "Alfreds Futterkiste");
}

[Description("This sample uses WHERE to find all orders placed before 1997.")]
public void LinqToEntities02() {
var metadata =
EntityMetadataStore.Instance.GetEntityMetadata(typeof(InternationalOrder));
DateTime dt = new DateTime(1997, 1, 1);
var query = from order in _em1.Orders
where order.OrderDate < dt
orderby order.OrderDate
select order;
Assert.IsTrue(query.First().Freight == 32.38M);
}

[Description("This sample uses WHERE to filter for Products that have stock below their
reorder level and have a units on]
public void LinqToEntities03() {
var query = from p in _em1.Products
where p.UnitsInStock < p.ReorderLevel && p.UnitsOnOrder == 0
orderby p.UnitsInStock
select p;
Assert.IsTrue(query.First().ProductName == "Nord-Ost Matjeshering");
}

[Description("This sample uses WHERE to filter out Products that have a UnitPrice less
than 10.")]
public void LinqToEntities04() {
var query = from p in _em1.Products
where p.UnitPrice < 10
orderby p.ProductName
select p;
Assert.IsTrue(query.First().ProductName == "Filo Mix");
}

[Description("This sample uses WHERE to find Employees in London.")]
public void LinqToEntities04a() {
var query = from e in _em1.Employees
where e.Address.City == "London"
orderby e.EmployeeID
select e;
Assert.IsTrue(query.First().LastName == "Buchanan");
}

[Description("This sample uses WHERE to get previous employees.")]
public void LinqToEntities05() {
var query = from e in _em1.Employees
where e is PreviousEmployee
orderby e.EmployeeID
select e;
var r = query.ToList();
Assert.IsTrue(r.First().LastName == "King");
}

[Description("This sample uses WHERE to get employees who handle the Boston
territory.")]
public void LinqToEntities06() {

var query = from e in _em1.Employees.OfType<CurrentEmployee>()
where e.Territories.Any(t => t.TerritoryDescription == "Boston")
orderby e.EmployeeID
select e;
Assert.IsTrue(query.First().LastName == "Fuller");
}

[Description("This sample uses any Customers who placed an order in 1997.")]
public void LinqToEntities07() {
var query = from c in _em1.Customers
where c.Orders.Any(o => o.OrderDate.HasValue == true &&
o.OrderDate.Value.Year == 1997)
select c;
Assert.IsTrue(query.Count() == 85);
}

[Description("This sample uses ANY to check for any out-of-stock products.")]
public void LinqToEntities08() {
var query = _em1
.Suppliers
.Where(s => s.Products
.Any(p => p.UnitsInStock == 0))
.Select(s => s);
Assert.IsTrue(query.Count() == 5);
}

[Description("This sample uses WHERE and ANY to get orders containing a product
with a unit on order.")]
public void LinqToEntities09() {
var query = from o in _em1.Orders
where o.OrderDetails.Any(od => od.Product.UnitsOnOrder > 0)
select o;
Assert.IsTrue(query.ToList().Count == 366);
Assert.IsTrue(query.Count() == 366);
}

[Description("This sample uses COUNT to get Products sold to Customers in the same
Country " +
"as the Products' Suppliers, and where all the Products in the order were from the same
Country.")]
public void LinqToEntities10() {
var query = from p in _em1.Products
where p.OrderDetails.Count(od => od.Order.Customer.Address.Country ==
p.Supplier.Address.Country) > 2
select p;
Assert.IsTrue(query.Count() == 20);
}
VB

<Description("This sample uses WHERE to find all customers whose contact title is Sales
Representative.")>
Public Sub LinqToEntities01()

Dim query = From cust In _em1.Customers
Where cust.ContactTitle = "Sales Representative"
Order By cust.CompanyName
Select cust
Dim r = query.ToList()
Assert.IsTrue(r.First().CompanyName = "Alfreds Futterkiste")
End Sub

<Description("This sample uses WHERE to find all orders placed before 1997.")>
Public Sub LinqToEntities02()
Dim metadata =
EntityMetadataStore.Instance.GetEntityMetadata(GetType(InternationalOrder))
Dim dt As New Date(1997, 1, 1)
Dim query = From order In _em1.Orders
Where order.OrderDate < dt
Order By order.OrderDate
Select order
Assert.IsTrue(query.First().Freight = 32.38D)
End Sub

<Description("This sample uses WHERE to filter for Products that have stock below their
reorder level and have a units on>
Public Sub LinqToEntities03()
Dim query = From p In _em1.Products
Where p.UnitsInStock < p.ReorderLevel AndAlso p.UnitsOnOrder = 0
Order By p.UnitsInStock
Select p
Assert.IsTrue(query.First().ProductName = "Nord-Ost Matjeshering")
End Sub

<Description("This sample uses WHERE to filter out Products that have a UnitPrice less
than 10.")>
Public Sub LinqToEntities04()
Dim query = From p In _em1.Products
Where p.UnitPrice < 10
Order By p.ProductName
Select p
Assert.IsTrue(query.First().ProductName = "Filo Mix")
End Sub

<Description("This sample uses WHERE to find Employees in London.")>
Public Sub LinqToEntities04a()
Dim query = From e In _em1.Employees
Where e.Address.City = "London"
Order By e.EmployeeID
Select e
Assert.IsTrue(query.First().LastName = "Buchanan")
End Sub

<Description("This sample uses WHERE to get previous employees.")>
Public Sub LinqToEntities05()
Dim query = From e In _em1.Employees
Where TypeOf e Is PreviousEmployee
Order By e.EmployeeID
Select e
Dim r = query.ToList()
Assert.IsTrue(r.First().LastName = "King")
End Sub

<Description("This sample uses WHERE to get employees who handle the Boston
territory.")>
Public Sub LinqToEntities06()

Dim query = From e In _em1.Employees.OfType(Of CurrentEmployee)()
Where e.Territories.Any(Function(t) t.TerritoryDescription = "Boston")
Order By e.EmployeeID
Select e
Assert.IsTrue(query.First().LastName = "Fuller")
End Sub

<Description("This sample uses any Customers who placed an order in 1997.")>
Public Sub LinqToEntities07()
Dim query = From c In _em1.Customers
Where c.Orders.Any(Function(o) o.OrderDate.HasValue = True AndAlso
o.OrderDate.Value.Year = 1997)
Select c
Assert.IsTrue(query.Count() = 85)
End Sub

<Description("This sample uses ANY to check for any out-of-stock products.")>
Public Sub LinqToEntities08()
Dim query = _em1.Suppliers.Where(Function(s) s.Products.Any(Function(p)
p.UnitsInStock = 0)).Select(Function(s) s)
Assert.IsTrue(query.Count() = 5)
End Sub

<Description("This sample uses WHERE and ANY to get orders containing a product
with a unit on order.")>
Public Sub LinqToEntities09()
Dim query = From o In _em1.Orders
Where o.OrderDetails.Any(Function(od) od.Product.UnitsOnOrder > 0)
Select o
Assert.IsTrue(query.ToList().Count = 366)
Assert.IsTrue(query.Count() = 366)
End Sub

<Description("This sample uses COUNT to get Products sold to Customers in the same
Country " & "as the Products' Suppliers, and where all the Products in the order were
from the same Country.")>
Public Sub LinqToEntities10()
Dim query = From p In _em1.Products
Where p.OrderDetails.Count(Function(od) od.Order.Customer.Address.Country
= p.Supplier.Address.Country) > 2
Select p
Assert.IsTrue(query.Count() = 20)
End Sub


Projection operators - Select, SelectMany, anonymous projections
Examples of the LINQ Select and SelectMany operators are shown below. In the examples
below _em1 is an EntityManager.
C#
[Description("This samples uses SELECT to get all Customers as Entity Objects.")]
public void LinqToEntities11() {
var query = from c in _em1.Customers
select c;
Assert.IsTrue(query.Count() == 91);
}

[Description("This samples uses SELECT to get all Customer Contact Names as
Strings.")]
public void LinqToEntities12() {
var query = from c in _em1.Customers
orderby c.ContactName
select c.ContactName;
var r = query.ToList();
Assert.IsTrue(r.First() == "Alejandra Camino");
}

[Description("This samples uses SELECT to get all Customer Contact Names as an
anonoymous type.")]
public void LinqToEntities13() {
var query = from c in _em1.Customers
orderby c.CompanyName
select new { c.ContactName };

var r = query.ToList();
Assert.IsTrue(r.First().ContactName == "Maria Anders");
}

[Description("This sample uses SELECT to get Orders as anonymous type")]
public void LinqToEntities14() {
var query = from o in _em1.Orders
where o.Customer.Address.City == "London"
orderby o.OrderDate
select new { o };

var r = query.ToList();
Assert.IsTrue(r.Count() == 46);
Assert.IsTrue(r.First().o.OrderDate == new DateTime(1996, 8, 26));
}

[Description("This sample uses SELECT to get all Orders and associated Customers as
anonymous type")]
public void LinqToEntities15() {
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly;
var query = from o in _em1.Orders
where o.Customer.Address.City == "London"
orderby o.Customer.CompanyName descending
select new { o, o.Customer };

var r = query.ToList();
Assert.IsTrue(r.Count() == 46);
Assert.IsTrue(r.First().Customer.CompanyName == "Seven Seas Imports");
}

[Description("This sample uses SELECTMANY to get all Orders for a Customer as a flat
result")]
public void LinqToEntities16() {
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly;
var query = from c in _em1.Customers
where c.CustomerID == "ALFKI"
from o in c.Orders
orderby o.OrderDate
select o;

var r = query.ToList();
Assert.IsTrue(r.Count() == 6);
Assert.IsTrue(r.First().OrderDate == new DateTime(1997, 8, 25));
}

[Description("This sample uses SELECTMANY to get all Orders for a Customer as a flat
result as a method query")]
public void LinqToEntities17() {
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly;
var query = _em1.Customers.Where(cust => cust.CustomerID == "ALFKI")
.SelectMany(cust => cust.Orders
.OrderBy(o => o.OrderDate));

var r = query.ToList();
Assert.IsTrue(r.Count() == 6);
Assert.IsTrue(r.First().OrderDate == new DateTime(1997, 8, 25));
}

[Description("This sample uses SELECTMANY to get all Orders for Customers in
Denmark as a flat result")]
public void LinqToEntities18() {
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly;
var query = from c in _em1.Customers
where c.Address.Country == "Denmark"
from o in c.Orders
orderby o.OrderDate
select o;

var r = query.ToList();
Assert.IsTrue(r.Count() == 18);
Assert.IsTrue(r.First().OrderDate == new DateTime(1996, 10, 29));
}

[Description("This sample uses SELECTMANY to get all Orders for Customers in
Denmark as a flat result as a method query")]
public void LinqToEntities19() {
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly;
var query = _em1.Customers.Where(cust => cust.Address.Country == "Denmark")
.SelectMany(cust => cust.Orders);

var r = query.ToList();
Assert.IsTrue(r.Count() == 18);
}


[Description("This sample uses SELECTMANY to get all Orders for Customers in
Denmark as a flat result")]
public void LinqToEntities20x() {
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly;
var query = from c in _em1.Customers
where c.Address.Country == "Denmark"
from o in c.Orders
where o.Freight > 5
orderby o.OrderDate
select o;

Assert.IsTrue(query.Count() == 17);
Assert.IsTrue(query.First().OrderDate == new DateTime(1996, 10, 29));
}

[Description("This sample uses SELECTMANY to get all Orders for Customers in
Denmark as an anonymous type containing the Orders and Customer flat result")]
public void LinqToEntities21x() {
_em1.DefaultQueryStrategy =
QueryStrategy.Normal.With(QueryInversionMode.Manual);
var query = from c in _em1.Customers
where c.Address.Country == "Denmark"
orderby c.CompanyName
from o in c.Orders
where o.Freight > 5
orderby o.OrderDate
select new { c, o};

Assert.IsTrue(query.Count() == 17);
var x = query.First();
Assert.IsTrue(query.First().o.OrderDate == new DateTime(1996, 10, 29));
}

[Description("This sample uses SELECTMANY to get all Orders for Customers in
Denmark as a flat result using LINQ opeartors")]
public void LinqToEntities22() {
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly;
var query = _em1
.Customers
.Where(cust => cust.Address.Country == "Denmark")
.SelectMany(cust => cust.Orders
.Where(o => o.Freight > 5)
.OrderBy(o => o.OrderDate));
var r = query.ToList();
Assert.IsTrue(r.Count() == 17);
Assert.IsTrue(r.First().OrderDate == new DateTime(1996, 10, 29));
}
VB
<Description("This samples uses SELECT to get all Customers as Entity Objects.")>
Public Sub LinqToEntities11()
Dim query = From c In _em1.Customers
Select c
Assert.IsTrue(query.Count() = 91)
End Sub

<Description("This samples uses SELECT to get all Customer Contact Names as
Strings.")>
Public Sub LinqToEntities12()
Dim query = From c In _em1.Customers
Order By c.ContactName
Select c.ContactName
Dim r = query.ToList()
Assert.IsTrue(r.First() = "Alejandra Camino")
End Sub

<Description("This samples uses SELECT to get all Customer Contact Names as an
anonoymous type.")>
Public Sub LinqToEntities13()
Dim query = From c In _em1.Customers
Order By c.CompanyName
Select New With {Key c.ContactName}

Dim r = query.ToList()
Assert.IsTrue(r.First().ContactName = "Maria Anders")
End Sub

<Description("This sample uses SELECT to get Orders as anonymous type")>
Public Sub LinqToEntities14()
Dim query = From o In _em1.Orders
Where o.Customer.Address.City = "London"
Order By o.OrderDate
Select New With {Key o}

Dim r = query.ToList()
Assert.IsTrue(r.Count() = 46)
Assert.IsTrue(r.First().o.OrderDate = New Date(1996, 8, 26))
End Sub

<Description("This sample uses SELECT to get all Orders and associated Customers as
anonymous type")>
Public Sub LinqToEntities15()
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly
Dim query = From o In _em1.Orders
Where o.Customer.Address.City = "London"
Order By o.Customer.CompanyName Descending
Select New With {Key o, Key o.Customer}

Dim r = query.ToList()
Assert.IsTrue(r.Count() = 46)
Assert.IsTrue(r.First().Customer.CompanyName = "Seven Seas Imports")
End Sub

<Description("This sample uses SELECTMANY to get all Orders for a Customer as a flat
result")>
Public Sub LinqToEntities16()
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly
Dim query = From c In _em1.Customers
Where c.CustomerID = "ALFKI"
From o In c.Orders
Order By o.OrderDate
Select o

Dim r = query.ToList()
Assert.IsTrue(r.Count() = 6)
Assert.IsTrue(r.First().OrderDate = New Date(1997, 8, 25))
End Sub

<Description("This sample uses SELECTMANY to get all Orders for a Customer as a flat
result as a method query")>
Public Sub LinqToEntities17()
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly
Dim query = _em1.Customers.Where(Function(cust) cust.CustomerID =
"ALFKI").SelectMany(Function(cust) cust.Orders.OrderBy(Function(o) o.OrderDate))

Dim r = query.ToList()
Assert.IsTrue(r.Count() = 6)
Assert.IsTrue(r.First().OrderDate = New Date(1997, 8, 25))
End Sub

<Description("This sample uses SELECTMANY to get all Orders for Customers in
Denmark as a flat result")>
Public Sub LinqToEntities18()
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly
Dim query = From c In _em1.Customers
Where c.Address.Country = "Denmark"
From o In c.Orders
Order By o.OrderDate
Select o

Dim r = query.ToList()
Assert.IsTrue(r.Count() = 18)
Assert.IsTrue(r.First().OrderDate = New Date(1996, 10, 29))
End Sub

<Description("This sample uses SELECTMANY to get all Orders for Customers in
Denmark as a flat result as a method query")>
Public Sub LinqToEntities19()
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly
Dim query = _em1.Customers.Where(Function(cust) cust.Address.Country =
"Denmark").SelectMany(Function(cust) cust.Orders)

Dim r = query.ToList()
Assert.IsTrue(r.Count() = 18)
End Sub


<Description("This sample uses SELECTMANY to get all Orders for Customers in
Denmark as a flat result")>
Public Sub LinqToEntities20x()
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly
Dim query = From c In _em1.Customers
Where c.Address.Country = "Denmark"
From o In c.Orders
Where o.Freight > 5
Order By o.OrderDate
Select o

Assert.IsTrue(query.Count() = 17)
Assert.IsTrue(query.First().OrderDate = New Date(1996, 10, 29))
End Sub

<Description("This sample uses SELECTMANY to get all Orders for Customers in
Denmark as an anonymous type containing the Orders and Customer flat result")>
Public Sub LinqToEntities21x()
_em1.DefaultQueryStrategy =
QueryStrategy.Normal.With(QueryInversionMode.Manual)
Dim query = From c In _em1.Customers
Where c.Address.Country = "Denmark"
Order By c.CompanyName
From o In c.Orders
Where o.Freight > 5
Order By o.OrderDate
Select New With {Key c, Key o}

Assert.IsTrue(query.Count() = 17)
Dim x = query.First()
Assert.IsTrue(query.First().o.OrderDate = New Date(1996, 10, 29))
End Sub

<Description("This sample uses SELECTMANY to get all Orders for Customers in
Denmark as a flat result using LINQ opeartors")>
Public Sub LinqToEntities22()
_em1.DefaultQueryStrategy = QueryStrategy.DataSourceOnly
Dim query = _em1.Customers.Where(Function(cust) cust.Address.Country =
"Denmark").SelectMany(Function(cust) cust.Orders.Where(Function(o) o.Freight >
5).OrderBy(Function(o) o.OrderDate))
Dim r = query.ToList()
Assert.IsTrue(r.Count() = 17)
Assert.IsTrue(r.First().OrderDate = New Date(1996, 10, 29))
End Sub

Ordering and Grouping operators - OrderBy, OrderByDescending, ThenBy,
ThenByDescending, GroupBy
Examples of the LINQ OrderBy, OrderByDescending, ThenBy, ThenByDescending and
GroupBy are shown below. In the examples below _em1 is an EntityManager.
C#
[Description("Select all customers ordered by ContactName.")]
public void LinqToEntities53() {
var query = from c in _em1.Customers
orderby c.ContactName
select c;
Assert.IsTrue(query.First().ContactName == "Alejandra Camino");
}

[Description("Select all customers ordered by ContactName descending.")]
public void LinqToEntities54() {
var query = from c in _em1.Customers
orderby c.CompanyName descending
select c;
Assert.IsTrue(query.First().CompanyName == "Wolski Zajazd");
}

[Description("Select an anonoymous type with all product IDs ordered by
UnitsInStock.")]
public void LinqToEntities55() {
var query = from p in _em1.Products
orderby p.UnitsInStock
select new { p.ProductID, p.UnitsInStock };
Assert.IsTrue(query.First().ProductID == 5);
}

[Description("Select an anonoymous type with all product IDs ordered by UnitsInStock as
a method query.")]
public void LinqToEntities56() {
var query = _em1.Products.OrderBy(p => p.UnitsInStock)
.Select(p2 => new { p2.ProductID, p2.UnitsInStock });
Assert.IsTrue(query.First().ProductID == 5);
Assert.IsTrue(query.First().UnitsInStock == 0);
}

[Description("Select all customers ordered by the descending region.")]
public void LinqToEntities57() {
var query = from c in _em1.Customers
orderby c.Address.Region descending
select c;
Assert.IsTrue(query.First().CustomerID == "SPLIR");
Assert.IsTrue(query.First().Address.Region == "WY");
}

[Description("Select all customers ordered by the descending region as a method
query.")]
public void LinqToEntities58() {
var query = _em1.Customers.Select(c => c).OrderByDescending(c2 =>
c2.Address.Region);
Assert.IsTrue(query.First().CustomerID == "SPLIR");
}

[Description("Select all customers ordered by the region, then the contact name.")]
public void LinqToEntities59() {
var query = _em1.Customers.Select(c => c)
.OrderBy(c => c.Address.Region).ThenBy(c => c.ContactName);
Assert.IsTrue(query.First().CustomerID == "ROMEY");
Assert.IsTrue(query.First().Address.City + "/" + query.First().ContactName ==
"Madrid/Alejandra Camino");
}

[Description("Select all customers ordered by the region in descending order, then the
contact name.")]
public void LinqToEntities60() {
var query = _em1.Customers.Select(c => c)
.OrderByDescending(c => c.Address.Region).ThenBy(c => c.ContactName);
Assert.IsTrue(query.First().CustomerID == "SPLIR");
}

[Description("Select all customers ordered by the region then the contact name in
descending order.")]
public void LinqToEntities61() {
var query = _em1.Customers.Select(c => c).OrderBy(c =>
c.Address.Region).ThenByDescending(c => c.ContactName);
Assert.IsTrue(query.First().CustomerID == "WOLZA");

////Alternate
//var query = _Em1.Customers.OrderBy(c => c.Address.Region).ThenByDescending(c
=> c.ContactName).Select(c => c);
}

[Description("Select all products ordered by the descending unit price.")]
public void LinqToEntities62() {
var query = from p in _em1.Products
orderby p.UnitPrice descending
select p;
Assert.IsTrue(query.First().ProductID == 38);

//// Alternate
//var query0 = _Em1.Products.OrderByDescending(p => p.UnitPrice).Select(p => p);
//Assert.IsTrue(query0.First().ProductID == 38);}
}

[Description("Select all orders for a customer ordered by date that the order was
placed.")]
public void LinqToEntities63() {

// Alternate:
//var query0 = _Em1.Customers.Where(c=>c.CustomerID == "ALFKI")
// .SelectMany(c => c.Orders).OrderBy(o => o.OrderDate);
//Assert.IsTrue(query0.First().OrderDate == new DateTime(1997,8,25));

var query = _em1.Customers.Where(cust => cust.CustomerID == "ALFKI")
.SelectMany(c => c.Orders.Select(o => o))
.OrderBy(o2 => o2.OrderDate);

Assert.IsTrue(query.First().OrderDate == new DateTime(1997, 8, 25));
}

[Description("Select all Regions with a customer.")]
public void LinqToEntities64() {
var query = from c in _em1.Customers
group c by c.Address.Region into regions
select new { regions.Key };
Assert.IsTrue(query.Count() == 19);

var query2 = query.OrderByDescending(r => r.Key);
Assert.IsTrue(query2.First().Key == "WY");
}

[Description("Select all dates with orders placed.")]
public void LinqToEntities65() {
var query = from o in _em1.Orders
group o by o.OrderDate into dates
select new { dates.Key };
Assert.IsTrue(query.Count() == 480);

var query2 = query.OrderBy(d => d.Key);
Assert.IsTrue(query2.First().Key == new DateTime(1996, 7, 4));
}

[Description("Select all Regions and customer count for each region.")]
public void LinqToEntities66() {
var query = from c in _em1.Customers
group c by c.Address.Region into regions
orderby regions.Key
select new { region = regions.Key, count = regions.Count() };
var r = query.ToList();

Assert.IsTrue(r.First().count == 60); // the variable count
}

[Description("Select all Regions and customer count for each region as a method
query.")]
public void LinqToEntities67() {
var query = _em1.Customers.GroupBy(c => c.Address.Region)
.OrderByDescending(r => r.Key)
.Select(r => new { region = r.Key, count = r.Count() });
Assert.IsTrue(query.First().count == 1);
}

[Description("Select all Customer Regions with the total Freight on all orders for
Customers in that Region.")]
public void LinqToEntities68() {
var query = from c in _em1.Customers
group c by c.Address.Region into regions
orderby regions.Key
join c2 in _em1.Customers on regions.Key equals c2.Address.Region
select new { region = regions.Key, total = c2.Orders.Sum(o => o.Freight) };
var r = query.ToList();
Assert.IsTrue(query.First().region == null);
Assert.IsTrue(query.First().total == 225.58M);
}

[Description("Select all Customer Regions with the total Freight on all orders for
Customers in that Region as a method query.")]
public void LinqToEntities69() {
var query = _em1.Customers.GroupBy(c => c.Address.Region)
.OrderBy(r => r.Key)
.Select(g => new {
Region = g.Key,
FreightTotal = g
.SelectMany(c2 => c2.Orders)
.Sum(o => o.Freight)
});

Assert.IsTrue(query.First().Region == null);
Assert.IsTrue(query.First().FreightTotal == 38063.31M);

var query2 = query.OrderByDescending(r => r.Region);
Assert.IsTrue(query2.First().Region == "WY");
Assert.IsTrue(query2.First().FreightTotal == 558.67M);
}
VB
<Description("Select all customers ordered by ContactName.")>
Public Sub LinqToEntities53()
Dim query = From c In _em1.Customers
Order By c.ContactName
Select c
Assert.IsTrue(query.First().ContactName = "Alejandra Camino")
End Sub

<Description("Select all customers ordered by ContactName descending.")>
Public Sub LinqToEntities54()
Dim query = From c In _em1.Customers
Order By c.CompanyName Descending
Select c
Assert.IsTrue(query.First().CompanyName = "Wolski Zajazd")
End Sub

<Description("Select an anonoymous type with all product IDs ordered by
UnitsInStock.")>
Public Sub LinqToEntities55()
Dim query = From p In _em1.Products
Order By p.UnitsInStock
Select New With {Key p.ProductID, Key p.UnitsInStock}
Assert.IsTrue(query.First().ProductID = 5)
End Sub

<Description("Select an anonoymous type with all product IDs ordered by UnitsInStock
as a method query.")>
Public Sub LinqToEntities56()
Dim query = _em1.Products.OrderBy(Function(p) p.UnitsInStock).Select(Function(p2)
New With {Key p2.ProductID, Key p2.UnitsInStock})
Assert.IsTrue(query.First().ProductID = 5)
Assert.IsTrue(query.First().UnitsInStock = 0)
End Sub

<Description("Select all customers ordered by the descending region.")>
Public Sub LinqToEntities57()
Dim query = From c In _em1.Customers
Order By c.Address.Region Descending
Select c
Assert.IsTrue(query.First().CustomerID = "SPLIR")
Assert.IsTrue(query.First().Address.Region = "WY")
End Sub

<Description("Select all customers ordered by the descending region as a method
query.")>
Public Sub LinqToEntities58()
Dim query = _em1.Customers.Select(Function(c) c).OrderByDescending(Function(c2)
c2.Address.Region)
Assert.IsTrue(query.First().CustomerID = "SPLIR")
End Sub

<Description("Select all customers ordered by the region, then the contact name.")>
Public Sub LinqToEntities59()
Dim query = _em1.Customers.Select(Function(c) c).OrderBy(Function(c)
c.Address.Region).ThenBy(Function(c) c.ContactName)
Assert.IsTrue(query.First().CustomerID = "ROMEY")
Assert.IsTrue(query.First().Address.City & "/" & query.First().ContactName =
"Madrid/Alejandra Camino")
End Sub

<Description("Select all customers ordered by the region in descending order, then the
contact name.")>
Public Sub LinqToEntities60()
Dim query = _em1.Customers.Select(Function(c) c).OrderByDescending(Function(c)
c.Address.Region).ThenBy(Function(c) c.ContactName)
Assert.IsTrue(query.First().CustomerID = "SPLIR")
End Sub

<Description("Select all customers ordered by the region then the contact name in
descending order.")>
Public Sub LinqToEntities61()
Dim query = _em1.Customers.Select(Function(c) c).OrderBy(Function(c)
c.Address.Region).ThenByDescending(Function(c) c.ContactName)
Assert.IsTrue(query.First().CustomerID = "WOLZA")

'//Alternate
'var query = _Em1.Customers.OrderBy(c => c.Address.Region).ThenByDescending(c =>
c.ContactName).Select(c => c);
End Sub

<Description("Select all products ordered by the descending unit price.")>
Public Sub LinqToEntities62()
Dim query = From p In _em1.Products
Order By p.UnitPrice Descending
Select p
Assert.IsTrue(query.First().ProductID = 38)

'// Alternate
'var query0 = _Em1.Products.OrderByDescending(p => p.UnitPrice).Select(p => p);
'Assert.IsTrue(query0.First().ProductID == 38);}
End Sub

<Description("Select all orders for a customer ordered by date that the order was
placed.")>
Public Sub LinqToEntities63()

' Alternate:
'var query0 = _Em1.Customers.Where(c=>c.CustomerID == "ALFKI")
' .SelectMany(c => c.Orders).OrderBy(o => o.OrderDate);
'Assert.IsTrue(query0.First().OrderDate == new DateTime(1997,8,25));

Dim query = _em1.Customers.Where(Function(cust) cust.CustomerID =
"ALFKI").SelectMany(Function(c) c.Orders.Select(Function(o)
o)).OrderBy(Function(o2) o2.OrderDate)

Assert.IsTrue(query.First().OrderDate = New Date(1997, 8, 25))
End Sub

<Description("Select all Regions with a customer.")>
Public Sub LinqToEntities64()
Dim query = From c In _em1.Customers
Group c By c.Address.Region Into regions = Group
Select New With {Key Region}
Assert.IsTrue(query.Count() = 19)

Dim query2 = query.OrderByDescending(Function(r) r.Key)
Assert.IsTrue(query2.First().Key = "WY")
End Sub

<Description("Select all dates with orders placed.")>
Public Sub LinqToEntities65()
Dim query = From o In _em1.Orders
Group o By o.OrderDate Into dates = Group
Select New With {Key OrderDate}
Assert.IsTrue(query.Count() = 480)

Dim query2 = query.OrderBy(Function(d) d.Key)
Assert.IsTrue(query2.First().Key = New Date(1996, 7, 4))
End Sub

<Description("Select all Regions and customer count for each region.")>
Public Sub LinqToEntities66()
Dim query = From c In _em1.Customers
Group c By c.Address.Region Into regions = Group
Order By Region
Select New With {Key .region = Region, Key .count = regions.Count()}
Dim r = query.ToList()

Assert.IsTrue(r.First().count = 60) ' the variable count
End Sub

<Description("Select all Regions and customer count for each region as a method
query.")>
Public Sub LinqToEntities67()
Dim query = _em1.Customers.GroupBy(Function(c)
c.Address.Region).OrderByDescending(Function(r) r.Key).Select(Function(r) New With
{Key .region = r.Key, Key .count = r.Count()})
Assert.IsTrue(query.First().count = 1)
End Sub

<Description("Select all Customer Regions with the total Freight on all orders for
Customers in that Region.")>
Public Sub LinqToEntities68()
Dim query = From c In _em1.Customers
Group c By c.Address.Region Into regions = Group
Order By Region
Join c2 In _em1.Customers On Region Equals c2.Address.Region
Select New With {Key .region = Region, Key .total = c2.Orders.Sum(Function(o)
o.Freight)}
Dim r = query.ToList()
Assert.IsTrue(query.First().region Is Nothing)
Assert.IsTrue(query.First().total = 225.58D)
End Sub

<Description("Select all Customer Regions with the total Freight on all orders for
Customers in that Region as a method query.")>
Public Sub LinqToEntities69()
Dim query = _em1.Customers.GroupBy(Function(c)
c.Address.Region).OrderBy(Function(r) r.Key).Select(Function(g) New With {Key
.Region = g.Key, Key .FreightTotal = g.SelectMany(Function(c2)
c2.Orders).Sum(Function(o) o.Freight)})

Assert.IsTrue(query.First().Region Is Nothing)
Assert.IsTrue(query.First().FreightTotal = 38063.31D)

Dim query2 = query.OrderByDescending(Function(r) r.Region)
Assert.IsTrue(query2.First().Region = "WY")
Assert.IsTrue(query2.First().FreightTotal = 558.67D)
End Sub

Aggregate operators - Count, Sum, Min, Max, Average
Examples of the LINQ Count, Sum, Min, Max and Average operators are shown below. In
the examples below _em1 is an EntityManager.
C#
[Description("This sample uses COUNT to get the number of Orders.")]
public void LinqToEntities23() {
var query = _em1.Orders.Count();
Assert.IsTrue(query == 830);
}

[Description("This sample uses COUNT to get the number of Orders placed by
Customers in Mexico.")]
public void LinqToEntities24() {
var query = _em1.Orders.Where(o => o.Customer.Address.Country ==
"Mexico").Count();
Assert.IsTrue(query == 28);
}

[Description("This sample uses COUNT to get the number of Orders shipped to
Mexico.")]
public void LinqToEntities25() {
var query = _em1.Orders
.Where(o => o.ShipCountry == "Mexico").Count();
Assert.IsTrue(query == 28);
}

[Description("This sample uses SUM to find the total freight over all Orders.")]
public void LinqToEntities26() {
var query = _em1.Orders.Select(o => o.Freight).Sum();
Assert.IsTrue(query == 64942.69M);
}

[Description("This sample uses SUM to find the total number of units on order over all
Products.")]
public void LinqToEntities27() {
var query = _em1.Products.Sum(p => p.UnitsOnOrder);
Assert.IsTrue(query == 780);
}

[Description("This sample uses SUM to find the total number of units on order over all
Products out-of-stock.")]
public void LinqToEntities28() {
var query = _em1.Products.Where(p => p.UnitsInStock == 0).Sum(p =>
p.UnitsOnOrder);
Assert.IsTrue(query == 70);
}

[Description("This sample uses MIN to find the lowest unit price of any Product.")]
public void LinqToEntities29() {
var query = _em1.Products.Select(p => p.UnitPrice).Min();
Assert.IsTrue(query == 2.5M);
}

[Description("This sample uses MIN to find the lowest freight of any Order.")]
public void LinqToEntities30() {
var query = _em1.Orders.Min(o => o.Freight);
Assert.IsTrue(query == 0.02M);
}

[Description("This sample uses MIN to find the lowest freight of any Order shipped to
Mexico.")]
public void LinqToEntities31() {
var query = _em1.Orders.Where(o => o.ShipCountry == "Mexico").Min(o =>
o.Freight);
Assert.IsTrue(query == 0.4M);
var query2 = _em1.Orders.Where(o => o.ShipCountry == "Mexico").Select(o =>
o.Freight).Min();
Assert.IsTrue(query2 == 0.4M);
}

[Description("This sample uses Min to find the Products that have the lowest unit price "
+
"in each category, and returns the result as an anonoymous type.")]
public void LinqToEntities32() {
var query = from p in _em1.Products
group p by p.Category.CategoryID into g
orderby g.Key
select new {
CategoryID = g.Key,
CheapestProducts =
from p2 in g
where p2.UnitPrice == g.Min(p3 => p3.UnitPrice)
select p2
};

var r = query.ToList();
Assert.IsTrue(r.Count() == 8);
Assert.IsTrue(r.First().CategoryID == 1);
Assert.IsTrue(r.First().CheapestProducts.First().UnitPrice == 4.5M);
}

[Description("This sample uses MAX to find the latest hire date of any Employee.")]
public void LinqToEntities33() {
var query = _em1.Employees.Select(e => e.HireDate).Max();
Assert.IsTrue(query == new DateTime(1994, 11, 15));
}

[Description("This sample uses MAX to find the most units in stock of any Product.")]
public void LinqToEntities34() {
var query = _em1.Products.Max(p => p.UnitsInStock);
Assert.IsTrue(query == 125);
}

[Description("This sample uses MAX to find the most units in stock of any Product with
CategoryID = 1.")]
public void LinqToEntities35() {
var query = _em1.Products.Where(p => p.Category.CategoryID == 2).Max(p =>
p.UnitsInStock);
Assert.IsTrue(query == 120);
}

[Description("This sample uses MAX to find the Products that have the " +
"highest unit price in each category, and returns the result as an anonoymous type.")]
public void LinqToEntities36() {
var query = from p in _em1.Products
group p by p.Category.CategoryID into g
orderby g.Key
select new {
g.Key,
MostExpensiveProducts =
from p2 in g
where p2.UnitPrice == g.Max(p3 => p3.UnitPrice)
orderby p2.UnitPrice
select p2
};

var r = query.ToList();
Assert.IsTrue(r.Count() == 8);
Assert.IsTrue(r.First().Key == 1);
Assert.IsTrue(r.First().MostExpensiveProducts.First().UnitPrice == 263.5M);
}

[Description("This sample uses AVERAGE to find the average freight of all Orders.")]
public void LinqToEntities37() {
var query = _em1.Orders.Select(o => o.Freight).Average();
Assert.IsTrue(query == 78.2442M);
}

[Description("This sample uses AVERAGE to find the average unit price of all
Products.")]
public void LinqToEntities38() {
var query = _em1.Products.Average(p => p.UnitPrice);
Assert.IsTrue(query == 28.8663M);
}

[Description("This sample uses AVERAGE to find the average unit price of all Products
with CategoryID = 1.")]
public void LinqToEntities39() {
var query = _em1.Products.Where(p => p.Category.CategoryID == 1)
.Average(p => p.UnitPrice);
Assert.IsTrue(query == 37.9791M);
}

[Description("This sample uses AVERAGE to find the Products that have unit price
higher than the average unit price of the category for each category.")]
public void LinqToEntities40() {

var query = from p in _em1.Products
group p by p.Category.CategoryID into g
orderby g.Key descending
select new {
g.Key,
ExpensiveProducts =
from p2 in g
where p2.UnitPrice > g.Average(p3 => p3.UnitPrice)
orderby p2.UnitPrice
select p2
};

var r = query.ToList();
Assert.IsTrue(r.Count() == 8);
Assert.IsTrue(r.First().Key == 8);
}

[Description("This sample uses AVERAGE to find the average unit price of each
category.")]
public void LinqToEntities41() {
var query = from p in _em1.Products
group p by p.Category.CategoryID into g
orderby g.Key descending
select new {
g.Key,
Average = g.Average(p => p.UnitPrice)
};
Assert.IsTrue(query.ToList().First().Key == 8);
Assert.IsTrue(query.First().Average == 20.6825M);
}
VB
<Description("This sample uses COUNT to get the number of Orders.")>
Public Sub LinqToEntities23()
Dim query = _em1.Orders.Count()
Assert.IsTrue(query = 830)
End Sub

<Description("This sample uses COUNT to get the number of Orders placed by
Customers in Mexico.")>
Public Sub LinqToEntities24()
Dim query = _em1.Orders.Where(Function(o) o.Customer.Address.Country =
"Mexico").Count()
Assert.IsTrue(query = 28)
End Sub

<Description("This sample uses COUNT to get the number of Orders shipped to
Mexico.")>
Public Sub LinqToEntities25()
Dim query = _em1.Orders.Where(Function(o) o.ShipCountry = "Mexico").Count()
Assert.IsTrue(query = 28)
End Sub

<Description("This sample uses SUM to find the total freight over all Orders.")>
Public Sub LinqToEntities26()
Dim query = _em1.Orders.Select(Function(o) o.Freight).Sum()
Assert.IsTrue(query Is 64942.69D)
End Sub

<Description("This sample uses SUM to find the total number of units on order over all
Products.")>
Public Sub LinqToEntities27()
Dim query = _em1.Products.Sum(Function(p) p.UnitsOnOrder)
Assert.IsTrue(query = 780)
End Sub

<Description("This sample uses SUM to find the total number of units on order over all
Products out-of-stock.")>
Public Sub LinqToEntities28()
Dim query = _em1.Products.Where(Function(p) p.UnitsInStock = 0).Sum(Function(p)
p.UnitsOnOrder)
Assert.IsTrue(query = 70)
End Sub

<Description("This sample uses MIN to find the lowest unit price of any Product.")>
Public Sub LinqToEntities29()
Dim query = _em1.Products.Select(Function(p) p.UnitPrice).Min()
Assert.IsTrue(query Is 2.5D)
End Sub

<Description("This sample uses MIN to find the lowest freight of any Order.")>
Public Sub LinqToEntities30()
Dim query = _em1.Orders.Min(Function(o) o.Freight)
Assert.IsTrue(query Is 0.02D)
End Sub

<Description("This sample uses MIN to find the lowest freight of any Order shipped to
Mexico.")>
Public Sub LinqToEntities31()
Dim query = _em1.Orders.Where(Function(o) o.ShipCountry =
"Mexico").Min(Function(o) o.Freight)
Assert.IsTrue(query Is 0.4D)
Dim query2 = _em1.Orders.Where(Function(o) o.ShipCountry =
"Mexico").Select(Function(o) o.Freight).Min()
Assert.IsTrue(query2 Is 0.4D)
End Sub

<Description("This sample uses Min to find the Products that have the lowest unit price "
& "in each category, and returns the result as an anonoymous type.")>
Public Sub LinqToEntities32()
Dim query = From p In _em1.Products
Group p By p.Category.CategoryID Into g = Group
Order By CategoryID
Select New With {Key .CategoryID = CategoryID, Key .CheapestProducts =
From p2 In g
Where p2.UnitPrice = g.Min(Function(p3) p3.UnitPrice)
Select p2}

Dim r = query.ToList()
Assert.IsTrue(r.Count() = 8)
Assert.IsTrue(r.First().CategoryID = 1)
Assert.IsTrue(r.First().CheapestProducts.First().UnitPrice = 4.5D)
End Sub

<Description("This sample uses MAX to find the latest hire date of any Employee.")>
Public Sub LinqToEntities33()
Dim query = _em1.Employees.Select(Function(e) e.HireDate).Max()
Assert.IsTrue(query Is New Date(1994, 11, 15))
End Sub

<Description("This sample uses MAX to find the most units in stock of any Product.")>
Public Sub LinqToEntities34()
Dim query = _em1.Products.Max(Function(p) p.UnitsInStock)
Assert.IsTrue(query = 125)
End Sub

<Description("This sample uses MAX to find the most units in stock of any Product with
CategoryID = 1.")>
Public Sub LinqToEntities35()
Dim query = _em1.Products.Where(Function(p) p.Category.CategoryID =
2).Max(Function(p) p.UnitsInStock)
Assert.IsTrue(query = 120)
End Sub

<Description("This sample uses MAX to find the Products that have the " & "highest unit
price in each category, and returns the result as an anonoymous type.")>
Public Sub LinqToEntities36()
Dim query = From p In _em1.Products
Group p By p.Category.CategoryID Into g = Group
Order By CategoryID
Select New With {Key CategoryID, Key .MostExpensiveProducts =
From p2 In g
Where p2.UnitPrice = g.Max(Function(p3) p3.UnitPrice)
Order By p2.UnitPrice
Select p2}

Dim r = query.ToList()
Assert.IsTrue(r.Count() = 8)
Assert.IsTrue(r.First().Key = 1)
Assert.IsTrue(r.First().MostExpensiveProducts.First().UnitPrice = 263.5D)
End Sub

<Description("This sample uses AVERAGE to find the average freight of all Orders.")>
Public Sub LinqToEntities37()
Dim query = _em1.Orders.Select(Function(o) o.Freight).Average()
Assert.IsTrue(query Is 78.2442D)
End Sub

<Description("This sample uses AVERAGE to find the average unit price of all
Products.")>
Public Sub LinqToEntities38()
Dim query = _em1.Products.Average(Function(p) p.UnitPrice)
Assert.IsTrue(query Is 28.8663D)
End Sub

<Description("This sample uses AVERAGE to find the average unit price of all Products
with CategoryID = 1.")>
Public Sub LinqToEntities39()
Dim query = _em1.Products.Where(Function(p) p.Category.CategoryID =
1).Average(Function(p) p.UnitPrice)
Assert.IsTrue(query Is 37.9791D)
End Sub

<Description("This sample uses AVERAGE to find the Products that have unit price
higher than the average unit price of the category for each category.")>
Public Sub LinqToEntities40()

Dim query = From p In _em1.Products
Group p By p.Category.CategoryID Into g = Group
Order By CategoryID Descending
Select New With {Key CategoryID, Key .ExpensiveProducts =
From p2 In g
Where p2.UnitPrice > g.Average(Function(p3) p3.UnitPrice)
Order By p2.UnitPrice
Select p2}

Dim r = query.ToList()
Assert.IsTrue(r.Count() = 8)
Assert.IsTrue(r.First().Key = 8)
End Sub

<Description("This sample uses AVERAGE to find the average unit price of each
category.")>
Public Sub LinqToEntities41()
Dim query = From p In _em1.Products
Group p By p.Category.CategoryID Into g = Group
Order By CategoryID Descending
Select New With {Key CategoryID, Key .Average = g.Average(Function(p)
p.UnitPrice)}
Assert.IsTrue(query.ToList().First().Key = 8)
Assert.IsTrue(query.First().Average = 20.6825D)
End Sub

Set operators - First, Distinct, Union, Concat, Interset, Except
Examples of the LINQ First, Distinct, Union, Concat, Intercept and Except operators are
shown below. In the examples below _em1 is an EntityManager.
C# [Description("This sample uses FIRST and WHERE to get the first (database order) order
that is shipped to Seattle. The WHERE predicate is evaluated on the server.")]
public void LinqToEntities42() {
var query = from o in _em1.Orders
where o.ShipCity == "Seattle"
orderby o.OrderID
select o;

var result = query.First();
Assert.IsTrue(result.OrderID == 10269);
}

[Description("This sample uses FIRST to get the first (database order) order that is
shipped to Seattle. The predicate is evaluated on the client.")]
public void LinqToEntities43() {
var query = from o in _em1.Orders
orderby o.OrderID
select o;
var result = query
.First(x => x.ShipCity == "Bern");
Assert.IsTrue(result.OrderID == 10254);
}

[Description("This sample uses FIRST, WHERE and ORDER BY to get the first order
that is shipped to Seattle, ordered by date. The predicate is evaluated on the server.")]
public void LinqToEntities44() {
var query = from o in _em1.Orders
where o.ShipCity == "Seattle"
orderby o.OrderDate
select o;

var result = query.First();
Assert.IsTrue(result.OrderID == 10269);
}

[Description("This sample uses DISTINCT to get all the categories of products.")]
public void LinqToEntities45() {
var query = _em1.Products.Select(o => o.Category).Distinct().OrderByDescending(c =>
c.CategoryName);
Assert.IsTrue(query.Count() == 8);
Assert.IsTrue(query.First().CategoryName == "Seafood");
}

[Description("This sample uses UNION to get all the orders where the shipping country
was Mexico or Canada.")]
public void LinqToEntities46() {
var mexico = _em1.Orders.Where(o => o.ShipCountry == "Mexico").Select(o => o);
var canada = _em1.Orders.Where(o => o.ShipCountry == "Canada").Select(o => o);
var query = mexico.Union(canada).OrderBy(o => o.OrderID);

Assert.IsTrue(query.Count() == 58);
Assert.IsTrue(query.First().OrderID == 10259);
}

[Description("This sample uses UNION and DISTINCT to get all the Customers from
orders where the shipping country was Mexico or Canada.")]
public void LinqToEntities47() {
var mexico = _em1.Orders.Where(o => o.ShipCountry == "Mexico").Select(o => o);
var canada = _em1.Orders.Where(o => o.ShipCountry == "Canada").Select(o => o);
var union = mexico.Union(canada).Select(o => o.Customer);

var query = union.Distinct().OrderByDescending(c => c.CompanyName);

Assert.IsTrue(query.Count() == 8);
Assert.IsTrue(query.First().CompanyName == "Tortuga Restaurante");
}

[Description("This sample uses CONCAT to get all orders where the shipping country
was Mexico or Canada.")]
public void LinqToEntities48() {
var mexico = _em1.Orders.Where(o => o.ShipCountry == "Mexico").OrderBy(o =>
o.OrderID).Select(o => o);
var canada = _em1.Orders.Where(o => o.ShipCountry == "Canada").OrderBy(o =>
o.OrderID).Select(o => o);

var query = mexico.Concat(canada);

Assert.IsTrue(query.Count() == 58);
var r = query.ToList();
Assert.IsTrue(r.First().OrderID == 10259);
}

[Description("This sample uses INTERSECT to get common products where an order
was shipped to Mexico or Canada.")]
public void LinqToEntities49() {
var mexico = _em1.OrderDetails.Where(od => od.Order.ShipCountry ==
"Mexico").OrderBy(o => o.ProductID).Select(od => od.Product);
var canada = _em1.OrderDetails.Where(od => od.Order.ShipCountry ==
"Canada").OrderBy(o => o.ProductID).Select(od => od.Product);

var query = mexico.Intersect(canada);

Assert.IsTrue(query.Count() == 24);
var productIds = query.Select(p => p.ProductID).ToList();
Assert.IsTrue(productIds.Contains(21));
}

[Description("This sample uses INTERSECT to get common products where an order
was shipped to Mexico " +
"or USA in one consolidated query.")]
public void LinqToEntities50() {
var query = _em1.OrderDetails.Where(od => od.Order.ShipCountry == "Mexico")
.Select(od => od.Product).Intersect(_em1.OrderDetails
.Where(od => od.Order.ShipCountry == "USA").Select(o => o.Product));
Assert.IsTrue(query.Count() == 44);
}

[Description("This sample uses EXCEPT to get customers who shipped orders to Mexico
but not Canada.")]
public void LinqToEntities51() {
var query = _em1.Orders.Where(o => o.ShipCountry == "Mexico")
.Select(o => o.Customer).Except(_em1.Orders
.Where(o => o.ShipCountry == "Canada").Select(o => o.Customer));
Assert.IsTrue(query.Count() == 5);
}

[Description("Variation on LinqToEntities51.")]
public void LinqToEntities51b() {
var mexico = _em1.Orders.Where(o => o.ShipCountry == "Mexico")
.Select(o => o.Customer);
var canada = _em1.Orders.Where(o => o.ShipCountry == "Canada")
.Select(o => o.Customer);
// diff => customers with orders shipping to Mexico but none shipping to Canada
var diff = mexico.Except(canada);

Assert.IsTrue(mexico.Count() == 28);
Assert.IsTrue(canada.Count() == 30);
Assert.IsTrue(diff.Count() == 5);
}

[Description("This sample uses EXCEPT to get customers with no orders sent to
Mexico.")]
public void LinqToEntities52() {
var query = _em1.Customers.Select(e => e)
.Except(_em1.Orders.Where(o => o.ShipCountry == "Mexico")
.Select(o => o.Customer));
Assert.IsTrue(query.Count() == 86);
}
VB
<Description("This sample uses FIRST and WHERE to get the first (database order)
order that is shipped to Seattle. The WHERE predicate is evaluated on the server.")>
Public Sub LinqToEntities42()
Dim query = From o In _em1.Orders
Where o.ShipCity = "Seattle"
Order By o.OrderID
Select o

Dim result = query.First()
Assert.IsTrue(result.OrderID = 10269)
End Sub

<Description("This sample uses FIRST to get the first (database order) order that is
shipped to Seattle. The predicate is evaluated on the client.")>
Public Sub LinqToEntities43()
Dim query = From o In _em1.Orders
Order By o.OrderID
Select o
Dim result = query.First(Function(x) x.ShipCity = "Bern")
Assert.IsTrue(result.OrderID = 10254)
End Sub

<Description("This sample uses FIRST, WHERE and ORDER BY to get the first order
that is shipped to Seattle, ordered by date. The predicate is evaluated on the server.")>
Public Sub LinqToEntities44()
Dim query = From o In _em1.Orders
Where o.ShipCity = "Seattle"
Order By o.OrderDate
Select o

Dim result = query.First()
Assert.IsTrue(result.OrderID = 10269)
End Sub

<Description("This sample uses DISTINCT to get all the categories of products.")>
Public Sub LinqToEntities45()
Dim query = _em1.Products.Select(Function(o)
o.Category).Distinct().OrderByDescending(Function(c) c.CategoryName)
Assert.IsTrue(query.Count() = 8)
Assert.IsTrue(query.First().CategoryName = "Seafood")
End Sub

<Description("This sample uses UNION to get all the orders where the shipping country
was Mexico or Canada.")>
Public Sub LinqToEntities46()
Dim mexico = _em1.Orders.Where(Function(o) o.ShipCountry =
"Mexico").Select(Function(o) o)
Dim canada = _em1.Orders.Where(Function(o) o.ShipCountry =
"Canada").Select(Function(o) o)
Dim query = mexico.Union(canada).OrderBy(Function(o) o.OrderID)

Assert.IsTrue(query.Count() = 58)
Assert.IsTrue(query.First().OrderID = 10259)
End Sub

<Description("This sample uses UNION and DISTINCT to get all the Customers from
orders where the shipping country was Mexico or Canada.")>
Public Sub LinqToEntities47()
Dim mexico = _em1.Orders.Where(Function(o) o.ShipCountry =
"Mexico").Select(Function(o) o)
Dim canada = _em1.Orders.Where(Function(o) o.ShipCountry =
"Canada").Select(Function(o) o)
Dim union = mexico.Union(canada).Select(Function(o) o.Customer)

Dim query = union.Distinct().OrderByDescending(Function(c) c.CompanyName)

Assert.IsTrue(query.Count() = 8)
Assert.IsTrue(query.First().CompanyName = "Tortuga Restaurante")
End Sub

<Description("This sample uses CONCAT to get all orders where the shipping country
was Mexico or Canada.")>
Public Sub LinqToEntities48()
Dim mexico = _em1.Orders.Where(Function(o) o.ShipCountry =
"Mexico").OrderBy(Function(o) o.OrderID).Select(Function(o) o)
Dim canada = _em1.Orders.Where(Function(o) o.ShipCountry =
"Canada").OrderBy(Function(o) o.OrderID).Select(Function(o) o)

Dim query = mexico.Concat(canada)

Assert.IsTrue(query.Count() = 58)
Dim r = query.ToList()
Assert.IsTrue(r.First().OrderID = 10259)
End Sub

<Description("This sample uses INTERSECT to get common products where an order
was shipped to Mexico or Canada.")>
Public Sub LinqToEntities49()
Dim mexico = _em1.OrderDetails.Where(Function(od) od.Order.ShipCountry =
"Mexico").OrderBy(Function(o) o.ProductID).Select(Function(od) od.Product)
Dim canada = _em1.OrderDetails.Where(Function(od) od.Order.ShipCountry =
"Canada").OrderBy(Function(o) o.ProductID).Select(Function(od) od.Product)

Dim query = mexico.Intersect(canada)

Assert.IsTrue(query.Count() = 24)
Dim productIds = query.Select(Function(p) p.ProductID).ToList()
Assert.IsTrue(productIds.Contains(21))
End Sub

<Description("This sample uses INTERSECT to get common products where an order
was shipped to Mexico " & "or USA in one consolidated query.")>
Public Sub LinqToEntities50()
Dim query = _em1.OrderDetails.Where(Function(od) od.Order.ShipCountry =
"Mexico").Select(Function(od)
od.Product).Intersect(_em1.OrderDetails.Where(Function(od) od.Order.ShipCountry =
"USA").Select(Function(o) o.Product))
Assert.IsTrue(query.Count() = 44)
End Sub

<Description("This sample uses EXCEPT to get customers who shipped orders to Mexico
but not Canada.")>
Public Sub LinqToEntities51()
Dim query = _em1.Orders.Where(Function(o) o.ShipCountry =
"Mexico").Select(Function(o) o.Customer).Except(_em1.Orders.Where(Function(o)
o.ShipCountry = "Canada").Select(Function(o) o.Customer))
Assert.IsTrue(query.Count() = 5)
End Sub

<Description("Variation on LinqToEntities51.")>
Public Sub LinqToEntities51b()
Dim mexico = _em1.Orders.Where(Function(o) o.ShipCountry =
"Mexico").Select(Function(o) o.Customer)
Dim canada = _em1.Orders.Where(Function(o) o.ShipCountry =
"Canada").Select(Function(o) o.Customer)
' diff => customers with orders shipping to Mexico but none shipping to Canada
Dim diff = mexico.Except(canada)

Assert.IsTrue(mexico.Count() = 28)
Assert.IsTrue(canada.Count() = 30)
Assert.IsTrue(diff.Count() = 5)
End Sub

<Description("This sample uses EXCEPT to get customers with no orders sent to
Mexico.")>
Public Sub LinqToEntities52()
Dim query = _em1.Customers.Select(Function(e)
e).Except(_em1.Orders.Where(Function(o) o.ShipCountry =
"Mexico").Select(Function(o) o.Customer))
Assert.IsTrue(query.Count() = 86)
End Sub

Paging operators - Take, Skip
Examples of the LINQ Take and Skip operators are shown below. In the examples below
_em1 is an EntityManager.
C#
[Description("This sample uses WHERE to find all customers whose contact title is Sales
Representative.")]
public void LinqToEntities96a() {

// Not a variation of LinqToEntities96, but no numbers were available here.

var customersQuery = _em1.Customers.OrderBy(c => c.CompanyName);
customersQuery.QueryStrategy = QueryStrategy.DataSourceOnly;
ICollection<Customer> customers = customersQuery.Skip(5).Take(5).ToList();
Assert.IsTrue(customers.Count() == 5);
customersQuery.QueryStrategy = QueryStrategy.CacheOnly;
Assert.IsTrue(customersQuery.Count() == 5);
}

[Description("Skip the most recent 2 orders from customers in London")]
public void LinqToEntities96() {
var query = _em1.Orders
.Where(o => o.Customer.Address.City == "London")
.OrderBy(o => o.OrderDate)
.Skip(2).Select(o => o);

Assert.IsTrue(query.First().OrderID == 10359);
}

[Description("Take the 2 most recent Orders ")]
public void LinqToEntities97() {
var query = _em1.Orders
.OrderBy(o => o.OrderDate)
.Take(2).Select(o => o);

Assert.IsTrue(query.Count() == 2);
Assert.IsTrue(query.First().OrderID == 10248);
}

[Description("Take the 10th to the 20th Orders, ordered by date ")]
public void LinqToEntities98() {
var query = _em1.Orders
.OrderBy(o => o.OrderDate)
.Skip(10).Take(10).Select(o => o);

query.QueryStrategy = QueryStrategy.DataSourceOnly; // because of skip operator

var r = query.ToList();
Assert.IsTrue(r.Count() == 10);
Assert.IsTrue(r.First().OrderID == 10258);
}

[Description("Use a page number variable to get the xth page")]
public void LinqToEntities99() {
int pageSize = 10;
int pageNumber = 4;

var query = _em1.Orders
.OrderBy(o => o.OrderDate)
.Skip(pageSize * pageNumber).Take(pageSize).Select(o => o);
query.QueryStrategy = QueryStrategy.DataSourceOnly;
var r = query.ToList();
Assert.IsTrue(r.Count() == pageSize);
Assert.IsTrue(r.First().OrderID == 10288);
}
VB
<Description("This sample uses WHERE to find all customers whose contact title is Sales
Representative.")>
Public Sub LinqToEntities96a()

' Not a variation of LinqToEntities96, but no numbers were available here.

Dim customersQuery = _em1.Customers.OrderBy(Function(c) c.CompanyName)
customersQuery.QueryStrategy = QueryStrategy.DataSourceOnly
Dim customers As ICollection(Of Customer) =
customersQuery.Skip(5).Take(5).ToList()
Assert.IsTrue(customers.Count() = 5)
customersQuery.QueryStrategy = QueryStrategy.CacheOnly
Assert.IsTrue(customersQuery.Count() = 5)
End Sub

<Description("Skip the most recent 2 orders from customers in London")>
Public Sub LinqToEntities96()
Dim query = _em1.Orders.Where(Function(o) o.Customer.Address.City = _
"London").OrderBy(Function(o) o.OrderDate).Skip(2).Select(Function(o) o)

Assert.IsTrue(query.First().OrderID = 10359)
End Sub

<Description("Take the 2 most recent Orders ")>
Public Sub LinqToEntities97()
Dim query = _em1.Orders.OrderBy(Function(o)
o.OrderDate).Take(2).Select(Function(o) o)

Assert.IsTrue(query.Count() = 2)
Assert.IsTrue(query.First().OrderID = 10248)
End Sub

<Description("Take the 10th to the 20th Orders, ordered by date ")>
Public Sub LinqToEntities98()
Dim query = _em1.Orders.OrderBy(Function(o)
o.OrderDate).Skip(10).Take(10).Select(Function(o) o)

query.QueryStrategy = QueryStrategy.DataSourceOnly ' because of skip operator

Dim r = query.ToList()
Assert.IsTrue(r.Count() = 10)
Assert.IsTrue(r.First().OrderID = 10258)
End Sub

<Description("Use a page number variable to get the xth page")>
Public Sub LinqToEntities99()
Dim pageSize As Integer = 10
Dim pageNumber As Integer = 4

Dim query = _em1.Orders.OrderBy(Function(o) o.OrderDate).Skip(pageSize * _
pageNumber).Take(pageSize).Select(Function(o) o)
query.QueryStrategy = QueryStrategy.DataSourceOnly
Dim r = query.ToList()
Assert.IsTrue(r.Count() = pageSize)
Assert.IsTrue(r.First().OrderID = 10288)
End Sub
Span operators Include
Examples of using DevForce Include operator are shown below. In the examples below _em1
is an EntityManager.
C#
[Description("Load OrderDetails with Orders ")]
public void LinqToEntities94() {
var query0 = _em1.Orders.Include("OrderDetails")
.Where(c => c.Customer.Address.City == "London").Select(o => o);

var query1 = query0.OrderBy(o => o.OrderID);
var r1 = query1.ToList();

var o1 = query1.First();
var count1 = o1.OrderDetails.Count();
Assert.IsTrue(count1 == 2);
}

[Description("Load OrderDetails and Products with Orders ")]
public void LinqToEntities95() {
var query = _em1.Orders
.Include("OrderDetails")
.Include("OrderDetails.Product")
.Take(3).Select(o => o);

var query2 = query.OrderByDescending(o => o.OrderID);
var r2 = query2.ToList();
var p = r2.First().OrderDetails.First().Product;
Assert.IsNotNull(p);
Assert.IsFalse(p.EntityAspect.IsNullOrPendingEntity);
}
VB
<Description("Load OrderDetails with Orders ")>
Public Sub LinqToEntities94()
Dim query0 = _em1.Orders.Include("OrderDetails").Where(Function(c) _
c.Customer.Address.City = "London").Select(Function(o) o)

Dim query1 = query0.OrderBy(Function(o) o.OrderID)
Dim r1 = query1.ToList()

Dim o1 = query1.First()
Dim count1 = o1.OrderDetails.Count()
Assert.IsTrue(count1 = 2)
End Sub

<Description("Load OrderDetails and Products with Orders ")>
Public Sub LinqToEntities95()
Dim query = _em1.Orders.Include("OrderDetails").Include _
("OrderDetails.Product").Take(3).Select(Function(o) o)

Dim query2 = query.OrderByDescending(Function(o) o.OrderID)
Dim r2 = query2.ToList()
Dim p = r2.First().OrderDetails.First().Product
Assert.IsNotNull(p)
Assert.IsFalse(p.EntityAspect.IsNullOrPendingEntity)
End Sub
Relationship navigation - Using navigation properties in a query
Examples of the LINQ queries involving property navigation are shown below. In the
examples below _em1 is an EntityManager.
C#
[Description("Select a sequence of all the orders for a customer using Select.")]
public void LinqToEntities70() {
var query = _em1.Customers
.Where(cust => cust.CustomerID == "ALFKI")
.Select(c => c.Orders.OrderBy(o => o.OrderDate).Select(o => o));

Assert.IsTrue(query.Count() == 1);
//query.First() is not available because this doesn't return a list
}

[Description("Select all the orders for a customer using SelectMany.")]
public void LinqToEntities71() {
var query = _em1.Customers
.Where(cust => cust.CustomerID == "ALFKI")
.SelectMany(c => c.Orders);
Assert.IsTrue(query.Count() == 6);
Assert.IsTrue(query.First().OrderDate == new DateTime(1997, 8, 25));
}

[Description("Select number of orders placed in 1998 for a customer.")]
public void LinqToEntities74() {
var query = _em1.Customers
.Where(cust => cust.CustomerID == "ALFKI")
.SelectMany(c => c.Orders)
.Where(o => o.OrderDate.HasValue == true && o.OrderDate.Value.Year == 1998);
Assert.IsTrue(query.Count() == 3);

var query2 = query.OrderBy(o => o.OrderDate);
Assert.IsTrue(query2.First().OrderDate == new DateTime(1998, 1, 15));
}

[Description("Select a customer and the sum of the freight of thier orders.")]
public void LinqToEntities73() {
var query = _em1.Customers
.Where(cust => cust.CustomerID == "ALFKI")
.Select(c => c.Orders.Sum(o => o.Freight));
Assert.IsTrue(query.First() == 225.58M);
}

[Description("Select customers with an order where the shipping address is the same as
the customers.")]
public void LinqToEntities75() {
var query = _em1.Customers
.Where(cust => cust.Orders
.Any(o => o.ShipAddress == cust.Address.Address))
.Select(c2 => c2);
Assert.IsTrue(query.Count() == 83);

var query2 = query.OrderBy(c => c.CompanyName);
Assert.IsTrue(query.First().CompanyName == "Alfreds Futterkiste");
}

[Description("Selects all regions with a customer, and shows the sum of orders for
customers for each region.")]
public void LinqToEntities76() {
var query = from c in _em1.Customers
group c by c.Address.Region into regions
join c2 in _em1.Customers on regions.Key equals c2.Address.Region
orderby regions.Key descending
select new { region = regions.Key, total = c2.Orders.Sum(o => o.Freight) };

// The orderby clause above only works if it *follows*, rather than precedes, the
// join statement. Somebody explain that to me sometime. - GTD

Assert.IsTrue(query.First().region == "WY");
Assert.IsTrue(query.First().total == 558.67M);
}
VB
<Description("Select a sequence of all the orders for a customer using Select.")>
Public Sub LinqToEntities70()
Dim query = _em1.Customers.Where(Function(cust) cust.CustomerID =
"ALFKI").Select(Function(c) c.Orders.OrderBy(Function(o)
o.OrderDate).Select(Function(o) o))

Assert.IsTrue(query.Count() = 1)
'query.First() is not available because this doesn't return a list
End Sub

<Description("Select all the orders for a customer using SelectMany.")>
Public Sub LinqToEntities71()
Dim query = _em1.Customers.Where(Function(cust) cust.CustomerID =
"ALFKI").SelectMany(Function(c) c.Orders)
Assert.IsTrue(query.Count() = 6)
Assert.IsTrue(query.First().OrderDate = New Date(1997, 8, 25))
End Sub

<Description("Select number of orders placed in 1998 for a customer.")>
Public Sub LinqToEntities74()
Dim query = _em1.Customers.Where(Function(cust) cust.CustomerID =
"ALFKI").SelectMany(Function(c) c.Orders).Where(Function(o) o.OrderDate.HasValue
= True AndAlso o.OrderDate.Value.Year = 1998)
Assert.IsTrue(query.Count() = 3)

Dim query2 = query.OrderBy(Function(o) o.OrderDate)
Assert.IsTrue(query2.First().OrderDate = New Date(1998, 1, 15))
End Sub

<Description("Select a customer and the sum of the freight of thier orders.")>
Public Sub LinqToEntities73()
Dim query = _em1.Customers.Where(Function(cust) cust.CustomerID =
"ALFKI").Select(Function(c) c.Orders.Sum(Function(o) o.Freight))
Assert.IsTrue(query.First() = 225.58D)
End Sub

<Description("Select customers with an order where the shipping address is the same as
the customers.")>
Public Sub LinqToEntities75()
Dim query = _em1.Customers.Where(Function(cust) cust.Orders.Any(Function(o)
o.ShipAddress = cust.Address.Address)).Select(Function(c2) c2)
Assert.IsTrue(query.Count() = 83)

Dim query2 = query.OrderBy(Function(c) c.CompanyName)
Assert.IsTrue(query.First().CompanyName = "Alfreds Futterkiste")
End Sub

<Description("Selects all regions with a customer, and shows the sum of orders for
customers for each region.")>
Public Sub LinqToEntities76()
Dim query = From c In _em1.Customers
Group c By c.Address.Region Into regions = Group Join c2 In _em1.Customers
On Region Equals c2.Address.Region
Order By Region Descending
Select New With {Key .region = Region, Key .total = c2.Orders.Sum(Function(o)
o.Freight)}

' The orderby clause above only works if it *follows*, rather than precedes, the
' join statement. Somebody explain that to me sometime. - GTD

Assert.IsTrue(query.First().region = "WY")
Assert.IsTrue(query.First().total = 558.67D)
End Sub

Join operators - When to use Join
This topic explains how to use the LINQ J oin() operator ... and why you should rarely use it.


LINQ has a J oin() operator. Developers who are new to Entity Framework (EF) are quick to
use it because "JOIN" is such a common SQL operation. Experienced EF developers prefer to
use subqueries and almost never need to use J oin().
Why? Primarily because the entity data model (EDM) represents relationships between
entities as associations. You build that model so you can escape the mechanical details and
think in object terms rather than database terms. You want to write anOrder.OrderDetails
without getting into the nitty-gritty of using an outer-left-join of Order.OrderID and
OrderDetail.OrderID. You'd prefer not to think about foreign keys at all; they're a concept
that is alien to object thinking.
The Join() operation breaks that abstraction. It necessarily forces you to think about precisely
how you get the OrderDetails related to an order. You have to express the Join() in terms of
Order.OrderID and OrderDetail.OrderID. Why do that if you don't have to?
All abstractions "leak" eventually; it's unavoidable in real world programming. But we strive
to retain the benefits of our abstractions while it is easy and prudent to do so.
Life without joins
Suppose we want to query for just those Customers that have placed an Order with our
company. In SQL you'd write a "JOIN". In EF LINQ you'd write a subquery instead and test
to see if there were any orders. That query written in comprehension syntax could look like
this:

query = from c in manager.Customers
where c.Orders.Any()
select c

results = query.ToList()
The manager variable in these examples is an instance of the NorthwindIBEntityManager
generated from a model that accesses the "NorthwindIB" tutorial database. If you prefer
method chaining (lambda) syntax you could write it this way:
C#
query = manager.Customers.Where(c => c.Orders.Any())
results = query.ToList();
VB
query = manager.Customers.Where(Function (c) c.Orders.Any())
results = query.ToList()
We're taking advantage of the fact that we've modeled the association between Customer and
Order. We never need to JOIN when we have an association.
You could have joined
You could have achieved the same effect with a LINQ Join(). First with comprehension
syntax.

query = from c in manager.Customers
join o in manager.Orders
on c.CustomerID equals o.CustomerID
select c

results = query.Distinct().ToList()
That's a lot of messy detail. We're fortunate that Customer has a single value key; it gets very
messy if Customer has a composite key. Don't forget the Distinct() method or you'll get 800+
Customers, one for every Order in the tutorial database, when you only want the ~80 distinct
Customers.
Here it is again in method chaining (lambda) syntax:
C#
query = manager
.Customers // Customers
.Join(manager.Orders, // Orders
c => c.CustomerID, // Customers key
o => o.CustomerID, // Order key
(c, o) => c); // projected value (the "select")

results = query.Distinct().ToList();
VB
query = manager
.Customers ' Customers
.Join(manager.Orders, ' Orders
Function(c) c.CustomerID, ' Customers key
Function(o) o.CustomerID, ' Order key
Function(c, o) c) ' projected value (the "select")

results = query.Distinct().ToList()
When you have to join
Occasionally you know that two entities are related even though there is no association in the
model.
Imagine that the Employee entity has a deprecated key (EmployeeNumber) which remains the
only basis for linking to historical data (OldEmployeeData). Entity Framework won't let you
associate a dependent entity's key (OldEmployeeData.EmployeeNumber) with a non-primary
key of the parent (Employee.EmployeeNumber). You'll have to join them.
We don't have data like that in the DevForce "NorthwindIB" tutorial database so we'll make
up an absurd example in which you query for the Employees whose IDs happen also to be
Product IDs. You can join these entities yourself; Employee and Product have integer IDs
with values that overlap.
The values that you join must be comparable with equality. A common mistake is to join on two
properties that have different data types. You'll learn of your error in a runtime exception.
Here's the query in comprehension syntax:

query = from e in manager.Employees
join p in manager.Products
on e.EmployeeID equals p.ProductID
select e

results = query.ToList()
The results include all nine Employees in the "NorthwindIB" tutorial database; they happen to
have ids in the range {1..9} as do the first nine Products.
Distinct() wasn't necessary because the query compares primary key values which are
necessarily unique. Here's the same query in method chaining (lambda) syntax:
C#
query = manager
.Employees
.Join(
manager.Products,
e => e.EmployeeID,
p => p.ProductID,
(e, p) => e);

results = query.ToList();
VB
query = manager
.Employees
.Join(
manager.Products,
Function(e) e.EmployeeID,
Function(p) p.ProductID,
Function(e, p) e)

results = query.ToList()

Using closures
Examples of using closures with a LINQ query are shown below. In the examples below
_em1 is an EntityManager.
C#
class MyClass {
public static decimal Val = 50;

public decimal GetVal() {
return MyClass.Val;
}
}

[Description("Uses a local variable as a query parameter.")]
public void LinqToEntities91() {
MyClass c = new MyClass();

var query = _em1.Orders
.Where(o => o.Freight > MyClass.Val).Select(o => o);
Assert.IsTrue(query.Count() == 360);
}

[Description("Uses a the value of the local variable at query execution time.")]
public void LinqToEntities92() {
decimal x = 50;
var query = _em1.Orders.Where(o => o.Freight > x).Select(o => new { o.Freight, o });
Assert.IsTrue(query.Count() == 360);
x = 100;
Assert.IsTrue(query.Count() == 187);
}
VB
Friend Class MyClass
Public Shared Val As Decimal = 50

Public Function GetVal() As Decimal
Return MyClass.Val
End Function
End Class

<Description("Uses a local variable as a query parameter.")>
Public Sub LinqToEntities91()
Dim c As New MyClass()

Dim query = _em1.Orders.Where(Function(o) o.Freight >
MyClass.Val).Select(Function(o) o)
Assert.IsTrue(query.Count() = 360)
End Sub

<Description("Uses a the value of the local variable at query execution time.")>
Public Sub LinqToEntities92()
Dim x As Decimal = 50
Dim query = _em1.Orders.Where(Function(o) o.Freight > x).Select(Function(o) New
With {Key o.Freight, Key o})
Assert.IsTrue(query.Count() = 360)
x = 100
Assert.IsTrue(query.Count() = 187)
End Sub

Inheritance operators OfType
Examples of the LINQ OfType operator are shown below. In the examples below _em1 is an
EntityManager.
C#
[Description("Select all products, both active and discontinued products, and show the
type.")]
public void LinqToEntities77() {
var query = _em1
.Products
.Select(p => p);

var query2 = query
// force local execution to show local type
.AsEnumerable()
.Select(p => new { type = p.GetType().ToString(), prod = p });

StringBuilder msg = new StringBuilder();
foreach (var aProduct in query2) {
msg.Append("(" + aProduct.type + ") " + aProduct.prod.ProductName +
Environment.NewLine);
}
// set break point and inspect msg.ToString() as desired

var query3 = query2.OrderBy(p => p.prod.ProductName);
Assert.IsTrue(query3.First().prod.ProductName == "Alice Mutton");
}

[Description("Select only discontinued products.")]
public void LinqToEntities78() {
var query = _em1.Products.OfType<DiscontinuedProduct>().Select(p => p);
var r = query.ToList();
Assert.IsTrue(r.Count() == 8);
}

[Description("Select only products, which will reutrn all Products and subtypes of
Products (DiscontinuedProducts and ActiveProducts).")]
public void LinqToEntities79() {
var query = _em1.Products.OfType<Product>().Select(p => p);
Assert.IsTrue(query.Count() == 77);
}
[Description("Select only discontinued products.")]
public void LinqToEntities80() {
// Similar to LinqToEntities78; no .Select clause
var query = _em1.Products.OfType<DiscontinuedProduct>();
Assert.IsTrue(query.Count() == 8);
}

[TestMethod]
[Description("Select only discontinued products.")]
public void LinqToEntities81() {
var query = _em1.Products
.Where(p => p is DiscontinuedProduct);
Assert.IsTrue(query.Count() == 8);
}

[Description("Select all current employees.")]
public void LinqToEntities87() {
var query = _em1.Employees.OfType<CurrentEmployee>()
.ToList().Select(p => new { type = p.GetType().ToString(), p });
Assert.IsTrue(query.Count() >= 8);
int lastId = query.OrderBy(e => e.p.EmployeeID).Last().p.EmployeeID;
var query2 = query.OrderByDescending(e => e.p.EmployeeID);
Assert.IsTrue(query2.First().p.EmployeeID == lastId);
}
VB
<Description("Select all products, both active and discontinued products, and show the
type.")>
Public Sub LinqToEntities77()
Dim query = _em1.Products.Select(Function(p) p)

' force local execution to show local type
Dim query2 = query.AsEnumerable().Select(Function(p) New With {Key .type =
p.GetType().ToString(), Key .prod = p})

Dim msg As New StringBuilder()
For Each aProduct In query2
msg.Append("(" & aProduct.type & ") " & aProduct.prod.ProductName &
Environment.NewLine)
Next aProduct
' set break point and inspect msg.ToString() as desired

Dim query3 = query2.OrderBy(Function(p) p.prod.ProductName)
Assert.IsTrue(query3.First().prod.ProductName = "Alice Mutton")
End Sub

<Description("Select only discontinued products.")>
Public Sub LinqToEntities78()
Dim query = _em1.Products.OfType(Of DiscontinuedProduct)().Select(Function(p) p)
Dim r = query.ToList()
Assert.IsTrue(r.Count() = 8)
End Sub

<Description("Select only products, which will reutrn all Products and subtypes of
Products (DiscontinuedProducts and ActiveProducts).")>
Public Sub LinqToEntities79()
Dim query = _em1.Products.OfType(Of Product)().Select(Function(p) p)
Assert.IsTrue(query.Count() = 77)
End Sub
<Description("Select only discontinued products.")>
Public Sub LinqToEntities80()
' Similar to LinqToEntities78; no .Select clause
Dim query = _em1.Products.OfType(Of DiscontinuedProduct)()
Assert.IsTrue(query.Count() = 8)
End Sub

<TestMethod, Description("Select only discontinued products.")>
Public Sub LinqToEntities81()
Dim query = _em1.Products.Where(Function(p) TypeOf p Is DiscontinuedProduct)
Assert.IsTrue(query.Count() = 8)
End Sub

<Description("Select all current employees.")>
Public Sub LinqToEntities87()
Dim query = _em1.Employees.OfType(Of
CurrentEmployee)().ToList().Select(Function(p) New With {Key .type =
p.GetType().ToString(), Key p})
Assert.IsTrue(query.Count() >= 8)
Dim lastId As Integer = query.OrderBy(Function(e)
e.p.EmployeeID).Last().p.EmployeeID
Dim query2 = query.OrderByDescending(Function(e) e.p.EmployeeID)
Assert.IsTrue(query2.First().p.EmployeeID = lastId)
End Sub

More query tips
In previous topics we've seen how to create a basic LINQ query, how to return part of an
entity, how to include related entities, and more. Here are a few more miscellaneous query
tips.


Create a Query with no EntityManager Attached
You're familiar with the auto-generated query properties in your domain-specific
EntityManager, that's what you're using whenever you do something like the following:
C#
var mgr = new NorthwindIBEntities();
var customerQuery = mgr.Customers;
VB
Dim mgr = New NorthwindIBEntities()
Dim customerQuery = mgr.Customers
These queries are "for" that EntityManager instance. If you use one of the query extension
methods such as Execute or ExecuteAsync, the query will be executed by the EntityManager
on which the query was created.
C# var list = customerQuery.Execute();
VB Dim list = customerQuery.Execute()
It's often useful to create a query that can be easily used with any EntityManager
however. Suppose your application requires multiple EntityManagers because you need
separate editing contexts - separate "sandboxes" - for contemporaneous editing sessions. You
know what queries you will need to support the sandbox scenarios. Because you will re-use
the query among several EntityManagers, you don't want to tie the query to any particular
EntityManager.
You can easily create a query without an EntityManager:
C# EntityQuery<Customer> query = new EntityQuery<Customer>();
VB Dim query As New EntityQuery(Of Customer)()
You then have a few choices for how you execute this query.
One is to use the query methods on the EntityManager:
C#
var mgr = new NorthwindIBEntities();
var list = mgr.ExecuteQuery(query);

// ... and on another EM ...

var mgr2 = new NorthwindIBEntities();
var list2 = mgr2.ExecuteQuery(query);
VB
Dim mgr = New NorthwindIBEntities()
Dim list = mgr.ExecuteQuery(query)

' ... and on another EM ...

Dim mgr2 = New NorthwindIBEntities()
Dim list2 = mgr2.ExecuteQuery(query)
You can also use the With extension method to target an EntityManager. You can use the
With method for either an "unattached" query or one created for another EntityManager.
C#
var query = manager.Customers;
var mgr2 = new NorthwindIBEntities();
var query2 = query.With(mgr2);
VB
Dim query = manager.Customers
Dim mgr2 = New NorthwindIBEntities()
Dim query2 = query.With(mgr2)
If you execute a query without "attaching" it to an EntityManager in some way the
DefaultManager will be used. The DefaultManager is a static property on the EntityManager
which can reference the first EntityManager created, a specific EntityManager, or
nothing. Use of the DefaultManager is deprecated, and we do not recommend it, as results
may often not be what you expect.
Existence queries: are there any entities that match?
If you need to determine whether one or more entities meets certain criteria without retrieving
the entities the Any LINQ operator is a good choice.
C#
string someName = "Some company name";
bool rc = manager.Customers.Any(c => c.CompanyName == someName);
VB
Dim someName As String = "Some company name"
Dim rc As Boolean = manager.Customers.Any(Function(c) c.CompanyName = someName)
As an "immediate execution" query, to use this asynchronously you must use AsScalarAsync:
C#
string someName = "Some company name";
var op = manager.Customers.AsScalarAsync().Any(c => c.CompanyName == someName);
op.Completed += (o, args) => { bool rc = args.Result; };
VB
Dim someName As String = "Some company name"
Dim op = manager.Customers.AsScalarAsync().Any(Function(c) c.CompanyName = someName)
AddHandler op.Completed, Sub(o, args) Dim rc As Boolean = args.Result
The Count operator is also useful here, if instead of returning a boolean you want the total
number matching the criteria.
Use FirstOrNullEntity
First, some explanation of First. The LINQ First operator, in all incarnations, will throw an
exception if no items are found. Since you probably don't want your program to terminate for
such a simple query, you're usually better off using either the standard LINQ FirstOrDefault
or the DevForce extension FirstOrNullEntity.
FirstOrDefault will return the first item or its default value. For a reference type such as an
entity the default value is null (Nothing in VB). It's often easier to work with null entities in
DevForce, so if you instead use FirstOrNullEntity either the first item matching the selection
criteria is returned, or the entity type's null entity.
As an immediate execution query, you must use AsScalarAsync to execute this query in
Silverlight.
C#
Employee emp = manager.Employees.FirstOrNullEntity(e => e.City == "Moscow");
// ... or ...
var op = manager.Employees.AsScalarAsync().FirstOrNullEntity(e => e.City == "Moscow");
VB
Dim emp As Employee = manager.Employees.FirstOrNullEntity(Function(e) e.City = "Moscow")
' ... or ...
Dim op = manager.Employees.AsScalarAsync().FirstOrNullEntity(Function(e) e.City = "Moscow")
First vs. Single
The LINQ Single operator returns the one and only element matching the selection criteria. If
multiple elements match the criteria, it throws. If no elements match the criteria, it
throws. This isn't some diabolical DevForce design, these are the rules of LINQ.
If you do decide to use Single, it's usually best to use either SingleOrDefault or for async
only, the DevForce extension SingleOrNullEntity, to ensure that the query won't fail if no item
is returned.
First vs. Take(1)
The LINQ Take operator is usually used to take one or more items. You can use Skip with
Take to skip items before taking; this is how paging is done.
Take is not an immediate execution query, which can be good news in some environments,
and doesn't use AsScalarAsync when executed asynchronously. It also always returns an
IEnumerable<T>, so even a Take(1) will return an IEnumerable with the element. If no
items matched the criteria then an empty enumeration is returned.
Query using an IN clause
If you've searched in vain for the LINQ equivalent to the SQL "In" clause, you can stop
worrying. LINQ uses the Contains operator to implement a query with search criteria for a
value in a list. (This is usually translated to a SQL "In" clause by the Entity Framework when
the SQL is generated.)
C#
var countryNames = new List<string> {"UK", "France", "Germany"};
var query = manager.Customers
.Where(c => countryNames.Contains(c.Country));
VB
Dim countryNames = New List(Of String) From {"UK", "France", "Germany"}
Dim query = manager.Customers.Where(Function(c) countryNames.Contains(c.Country))
There is one caveat here, however. Your contains list should be a List<T>, where "T" is a
numeric type, a string, a DateTime or a GUID. Why this restriction? The list has to meet
DevForce's requirements for known types. DevForce will automatically recognize these lists
as known types without any extra effort on your part. If you need some other List then you
will need to ensure it can be used in n-tier deployments. You also can't use an array, for
example using string[] above will fail in an n-tier deployment. This is due to an arcane data
contract naming issue, so don't say we didn't warn you.













































Query without using LINQ
In addition to the EntityQuery which supports the entire .NET LINQ syntax stack, DevForce
provides several other query types that do not support LINQ syntax.
These are the EntityKeyQuery, PassthruEsqlQuery and StoredProcQuery types for queries
using EntityKeys, Entity SQL and stored procedures, respectively.
Like the EntityQuery, these types all implement DevForces IEntityQuery interface.
Unlike the EntityQuery<T>, these query types are not composable, meaning that additional
clauses cannot be tacked onto them to further restrict or project the query results into another
form. In addition, the PassthruESQLQuery and the StoredProcQuery types do not provide in-
memory querying capabilities.
What these queries do provide that the EntityQuery<T> does not is that they may offer,
depending on the use case, better integration with existing database constructs, special
functionality or improved performance. However, in most cases the EntityQuery<T> is
usually a better choice, because of its greater flexibility.
Sample PassthruEsqlQuery
C#
PassthruEsqlQuery query = new PassthruEsqlQuery(typeof(Employee),
"SELECT VALUE e FROM Employees AS e Where e.EmployeeID < 10");
IEnumerable results = _em1.ExecuteQuery(query);
VB
Dim query As New PassthruEsqlQuery(GetType(Employee), _
"SELECT VALUE e FROM Employees AS e Where e.EmployeeID < 10")
Dim results As IEnumerable = _em1.ExecuteQuery(query)
Sample StoredProcQuery
C#
QueryParameter param01 = new QueryParameter("EmployeeID",1);
QueryParameter param02 = new QueryParameter("Year",1996);
StoredProcQuery query = new StoredProcQuery(typeof(Order));
query.Parameters.Add(param01);
query.Parameters.Add(param02);
// Note that a FunctionImport must be defined in the Entity Model
query.ProcedureName = "OrdersGetForEmployeeAndYear";
_em1.ExecuteQuery(query);
VB
Dim param01 As New QueryParameter("EmployeeID", 1)
Dim param02 As New QueryParameter("Year", 1996)
Dim query As New StoredProcQuery(GetType(Order))
query.Parameters.Add(param01)
query.Parameters.Add(param02)
' Note that a FunctionImport must be defined in the Entity Model
query.ProcedureName = "OrdersGetForEmployeeAndYear"
_em1.ExecuteQuery(query)


















Query by EntityKey

The EntityKey of an entity defines the unique identity of an entity. You can query by
EntityKey using the EntityKeyQuery.
The EntityKeyQuery
Because an EntityKey by definition uniquely identifies a single entity, the EntityKeyQuery is
optimized in a way that other query types cannot be. The EntityManager, given an EntityKey,
can determine by looking in its entity cache whether or not an entity with this key has already
been fetched from the database. For other query types, DevForce uses its query cache to
determine whether a query has already been executed.
The determination of whether a given query has already been executed against a database is a
DevForce performance enhancement. Even with an EntityKeyQuery, this optimization can be
suppressed by using the DataSourceOnly QueryStrategy.
Creating an EntityKeyQuery
There are two basic ways to create an EntityKeyQuery: with an EntityKey, or with a list of
EntityKeys called an EntityKeyList.
You might wonder how to obtain an EntityKey since it's a property of an Entity (through its
EntityAspect). You can construct an EntityKey if you know the entity type and the key values.
For example, if you want to build an EntityKey for Employee 1, you could do the following:
C# var key = new EntityKey(typeof(Employee), 1);
VB Dim key = New EntityKey(GetType(Employee), 1)
You can then build the EntityKeyQuery for this key. One easy way is to use the helper
method ToKeyQuery:
C# var query = key.ToKeyQuery();
VB Dim query = key.ToKeyQuery()
Or using the EntityKeyQuery constructor:
C# var query = new EntityKeyQuery(key);
VB Dim query = New EntityKeyQuery(key)
Building an EntityKeyQuery from a list of EntityKeys is similar. An EntityKeyList is simply a
strongly-typed collection of EntityKeys. All keys in the list must be for the same type or
abstract type.
C#
var key1 = new EntityKey(typeof(Employee), 1);
var key2 = new EntityKey(typeof(Employee), 2);
var keyList = new EntityKeyList(typeof(Employee), new[] { key1, key2 });
VB
Dim key1 = New EntityKey(GetType(Employee), 1)
Dim key2 = New EntityKey(GetType(Employee), 2)
Dim keyList = New EntityKeyList(GetType(Employee), { key1, key2 })
You can create the EntityKeyQuery from the list in familiar ways:
C#
var query = keyList.ToKeyQuery();
... or
var query = new EntityKeyQuery(keyList);
VB
Dim query = keyList.ToKeyQuery()
'...or
Dim query = New EntityKeyQuery(keyList)
With the query in hand then you can then do many of the usual things you might do with a
query. The EntityKeyQuery is not a LINQ query so not all features will be available to it, but
you can set its QueryStrategy and EntityManager, and execute it via the ExecuteAsync or
ExecuteQueryAsync methods.
Because the EntityKeyQuery is not a generically typed class, its result is a simple
IEnumerable. You can cast the result an IEnumerable<T>.
C# var employees = entityManager.ExecuteQuery(query).Cast<Employee>();
VB Dim employees = entityManager.ExecuteQuery(query).Cast(Of Employee)()
C#
entityManager.ExecuteQueryAsync(query), op => {
var items = op.Results.Cast<Employee>();
});
VB Dim employees = entityManager.ExecuteQuery(query).Cast(Of Employee)()
Disadvantages of the EntityKeyQuery
While the EntityKeyQuery has its uses, it has some pretty substantial shortcomings when
compared with a standard LINQ query. The biggest of these is that the EntityKeyQuery is not
composable. This means that we cannot apply any additional restrictions, projections,
ordering etc. on these queries. We can of course perform all of the operations on the results of
an EntityKeyQuery after the query query returns but the server will have still needed to
perform the entire query.
The second disadvantage of the EntityKeyQuery is that it is really only intended for small
numbers of EntityKeys. The reason for this is that these methods are implemented so that they
in effect create a large "IN" or "OR" query for all of the desired entities by key. The query
expression itself can therefore become very large for large numbers of entities. Expressions
that are this large will have performance impacts in both serialization as well as query
compilation. For those cases where very large numbers of entities need to be refreshed, it is
usually a better idea to write a "covering" query that is much smaller textually but returns
approximately the same results. You may find that even though you return more entities than
are needed with this covering query, the resulting overall performance is still better.
Query by Id
You might wonder how an EntityKeyQuery differs from a simple LINQ query by Id. For
example, instead of:
C#
var key = new EntityKey(typeof(Employee), 1);
var query = key.ToKeyQuery();
VB
Dim key = New EntityKey(GetType(Employee), 1)
Dim query = key.ToKeyQuery()
... we could instead have built an EntityQuery:
C#
var query = entityManager.Employees.Where(e => e.EmployeeID == 1);
//.. more useful, use an EntityQuery with FirstOrNullEntity()
var emp = entityManager.Employees.FirstOrNullEntity(e => e.EmployeeID == 1);
VB
Dim query = entityManager.Employees.Where(Function(e) e.EmployeeID = 1)
'.. more useful, use an EntityQuery with FirstOrNullEntity()
Dim emp = entityManager.Employees.FirstOrNullEntity(Function(e) e.EmployeeID = 1)

The primary difference to DevForce is that it doesn't know that the EntityQuery is querying only by
the EntityKey value, and will thus treat the query as any other query in terms of optimization: it will
look for the query in the QueryCache and if not present send the query to the datastore, even if the
queried entity was already in the entity cache. With the EntityKeyQuery, DevForce will first search
the entity cache for the requested entity, and only if not present send the query to the datastore.
A second difference is that the LINQ query allows you to return a null entity if the requested
entity was not found, while the EntityKeyQuery will return an empty enumeration.
Another difference is that the EntityQuery is composable, so you can use all standard LINQ
operators supported by the EntityQuery
Entity SQL (ESQL) queries
DevForce supports Entity SQL (ESQL) queries with its PassthruEsqlQuery() class. As with
all other query types, PassthruEsqlQuery implements the IEntityQuery interface.


API
There are several PassThruEsqlQuery costructor overloads:
C#
public PassthruEsqlQuery(Type returnType, String esql)

public PassthruEsqlQuery(Type returnType, Type queryableType, String esql)

public PassthruEsqlQuery(Type returnType, ParameterizedEsql parameterizedEsql)

public PassthruEsqlQuery(Type returnType, Type queryableType, ParameterizedEsql
parameterizedEsql)
VB
Public Sub New(ByVal returnType As Type, ByVal esql As String)

Public Sub New(ByVal returnType As Type, ByVal parameterizedEsql As
ParameterizedEsql)
End Sub

Public Sub New(ByVal returnType As Type, ByVal queryableType As Type, ByVal
parameterizedEsql As ParameterizedEsql)
End Sub
Simple queries
The simplest calls require only a return type and a valid ESQL expression as show below:
C#
var query0 = new PassthruEsqlQuery(typeof(Customer),
"SELECT VALUE c FROM Customers AS c Where c.Country == 'Brazil'");
var result0 = query.With(_em1).Execute().Cast<Customer>();

var query1 = new PassthruEsqlQuery(typeof(SalesOrderHeader),
"SELECT VALUE SalesOrderHeader FROM SalesOrderHeaders AS SalesOrderHeader
Where SalesOrderHeader.Customer.CustomerID < 10");
var results1 = q1.With(_em1).Execute().Cast<SalesOrderHeader>();

var query2 = new PassthruEsqlQuery(typeof(SalesPerson),
"SELECT VALUE sp FROM SalesPersons AS sp Where sp.Bonus > 2000");
var results2 = query2.With(_em1).Execute().Cast<SalesPerson>();
VB
Dim query0 = New PassthruEsqlQuery(GetType(Customer), _
"SELECT VALUE c FROM Customers AS c Where c.Country == 'Brazil'")
Dim result0 = query.With(_em1).Execute().Cast(Of Customer)()

Dim query1 = New PassthruEsqlQuery(GetType(SalesOrderHeader), _
"SELECT VALUE SalesOrderHeader FROM SalesOrderHeaders AS SalesOrderHeader
Where SalesOrderHeader.Customer.CustomerID < 10")
Dim results1 = q1.With(_em1).Execute().Cast(Of SalesOrderHeader)()

Dim query2 = New PassthruEsqlQuery(GetType(SalesPerson), _
"SELECT VALUE sp FROM SalesPersons AS sp Where sp.Bonus > 2000")
Dim results2 = query2.With(_em1).Execute().Cast(Of SalesPerson)()
Note that because the PassthruEsqlQuery class is not generic all of the results from executing
such a query must be cast to the appropriate result type.
Queries with parameters
Queries with parameters can also be used as shown below:
C#
var param = new QueryParameter("country", "Brazil");
var paramEsql = new ParameterizedEsql(
"SELECT VALUE c FROM Customers AS c Where c.Country > @country", param);
var query = new PassthruEsqlQuery(typeof(Customer), paramEsql);
var result1 = query.With(_em1).Execute().Cast<Customer>();

param.Value = "Germany";
var result2 = query.With(_em1).Execute().Cast<Customer>();
VB
Dim param = New QueryParameter("country", "Brazil")
Dim paramEsql = New ParameterizedEsql( _
"SELECT VALUE c FROM Customers AS c Where c.Country > @country", param)
Dim query = New PassthruEsqlQuery(GetType(Customer), paramEsql)
Dim result1 = query.With(_em1).Execute().Cast(Of Customer)()

param.Value = "Germany"
Dim result2 = query.With(_em1).Execute().Cast(Of Customer)()
Note that the value of the parameter can be changed and the same query re-executed,
returning different results.
More complex queries
So far all of the queries shown have involved queries where the source type or queryable type
of the query is the same as the return type. If this is not the case then we need to pass in both
types to the constructor. For example:
C#
var query1 = new PassthruEsqlQuery(typeof(Int32), typeof(Customer),
"SELECT VALUE Count(c.CustomerType) FROM Customers AS c Where
c.CustomerID < 10");
var result1 = query1.With(_em1).Execute().Cast<Int32>();

var query2 = new PassthruEsqlQuery(typeof(Decimal), typeof(SalesPerson),
"SELECT VALUE Sum(sp.Bonus) FROM SalesPersons AS sp Where sp.Bonus >
2000");
var result2 = query2.With(_em1).Execute().Cast<Decimal>();
VB
Dim query1 = New PassthruEsqlQuery(GetType(Int32), GetType(Customer), _
"SELECT VALUE Count(c.CustomerType) FROM Customers AS c Where
c.CustomerID < 10")
Dim result1 = query1.With(_em1).Execute().Cast(Of Int32)()

Dim query2 = New PassthruEsqlQuery(GetType(Decimal), GetType(SalesPerson), _
"SELECT VALUE Sum(sp.Bonus) FROM SalesPersons AS sp Where sp.Bonus >
2000")
Dim result2 = query2.With(_em1).Execute().Cast(Of Decimal)()
Additional notes
When you use Entity SQL, youre responsible for formulating a query string that constitutes a
valid query. If you goof, you wont know until you run it.
A PassthruEsqlQuery can only be executed with the DataSourceOnly query strategy.
DevForce does not currently support ESQL queries with anonymous projections.
Stored procedure queries
DevForce supports querying for entities using stored procedure queries. The need arises
most frequently when we require the entities resulting from an extraordinarily complex query
involving large volumes of intermediate data that are not themselves required on the client.
One might imagine a multi-step query that touched several tables, performed multi-way joins,
ordered and aggregated the intermediate results, and compared values with many thousands of
records, all so as to return a handful of qualifying results. All of the other data were needed
only to satisfy the query; the user wont see any of them and there is no point to transmitting
them to the client.
This is a clear case for a stored procedure because we can and should maximize performance
by performing all operations as close to the data source as possible.
Chances are that the entities returned by the stored procedure are entities we already know.
That procedure could be just an especially resource-consuming query for Order entities that
we retrieve and save in the usual way under normal circumstances.
TheStoredProcQuery is perfect for this situation. We define such a query, identify Order as
the query return type, and turn it loose on the database. We accept the sproc-selected Order
objects and work with them in our typical merry way.
Note that a stored procedure query, by its nature, must be executed by the database: we cant
run it against the entity cache. So we may not invoke it while the application is running
offline.

Suppose your data source includes a stored procedure named SalesByYear. It is defined as
follows: (This example uses SQL Server TSQL, but any stored procedure than is supported
via the Entity Framework will also be supported by DevForce).
TSQL
ALTER procedure "SalesbyYear"
@Beginning_Date DateTime, @Ending_Date DateTime
AS
SELECT OrderSummary.ShippedDate, OrderSummary.id, "Order Subtotals".Subtotal,
DATENAME(yy,ShippedDate) AS Year
FROM OrderSummary INNER JOIN "Order Subtotals"
ON OrderSummary.Id = "Order Subtotals".OrderSummaryId
WHERE OrderSummary.ShippedDate Between @Beginning_Date And @Ending_Date
Along with tables and views, stored procedures can be added to the model using the EDM
Designer. Adding the stored procedure above results in the following Function element in the
schema (SSDL) section of the Entity Model file:
XML <Function Name="SalesbyYear" Schema="dbo" Aggregate="false"
BuiltIn="false" NiladicFunction="false" IsComposable="false"
ParameterTypeSemantics="AllowImplicitConversion">
<Parameter Name="Beginning_Date" Type="datetime" Mode="In" />
<Parameter Name="Ending_Date" Type="datetime" Mode="In" />
</Function>
To make this conveniently available for calling directly off of our entitymanager (as you
would equally have to do to make it available on the ADO.NET ObjectContext), you must
also add a FunctionImport element to the conceptual model, using the EDM Designer (see
http://msdn.microsoft.com/en-us/library/bb896231.aspx for more information on the
mechanics of adding stored procedures to the Entity Model). The resulting FunctionImport
would be defined as follows within the CSDL portion of the model:
XML <FunctionImport Name="GetSalesByYear" EntitySet=
"SalesByYearResults" ReturnType=
"Collection(IdeaBladeTest1Model.EF.SalesbyYear)">
<Parameter Name="Beginning_Date" Type="DateTime" Mode="In" />
<Parameter Name="Ending_Date" Type="DateTime" Mode="In" />
</FunctionImport>
DevForce will generate query and execute methods into your EntityManager for every
function import in the conceptual model. In a Silverlight application, youd call the query
method to construct a query and then execute that query asynchronously; the execute method
cannot be used because it will execute the query synchronously.
C#
public IEnumerable<IdeaBladeTest1Model.SalesbyYear> GetSalesByYear(
Nullable<DateTime> Beginning_Date, Nullable<DateTime> Ending_Date) {}
public StoredProcQuery GetSalesByYearQuery(
Nullable<DateTime> Beginning_Date, Nullable<DateTime> Ending_Date) {}
VB
Public Function GetSalesByYear(ByVal Beginning_Date? As Date, _
ByVal Ending_Date? As Date) As _
IEnumerable(Of IdeaBladeTest1Model.SalesbyYear)
End Function
Public Function GetSalesByYearQuery(ByVal Beginning_Date? As Date, _
ByVal Ending_Date? As Date) As StoredProcQuery
End Function
Having done all of that in your Entity Model, you can now use the resultant methods as
shown below:
C#
var _em1 = new IdeaBladeTest1Entities();
DateTime dt1 = DateTime.Parse("1/1/1990");
DateTime dt2 = DateTime.Parse("1/1/2000");
var results = _em1.GetSalesByYear(dt1, dt2);
// Or asynchronously
IEnumerable results;
var q = _em1.GetSalesByYearQuery(dt1, dt2);
var op = _em1.ExecuteQueryAsync(q);
op.Completed += (o, e) => {
results = e.Results;
};
VB
Dim _em1 = New IdeaBladeTest1Entities()
Dim dt1 As Date = Date.Parse("1/1/1990")
Dim dt2 As Date = Date.Parse("1/1/2000")
Dim results = _em1.GetSalesByYear(dt1, dt2)
' Or asynchronously
Dim results As IEnumerable
Dim q = _em1.GetSalesByYearQuery(dt1, dt2)
Dim op = _em1.ExecuteQueryAsync(q)
AddHandler op.Completed, Sub(o, e) results = e.Results
Stored procedure entity navigation
Dot Navigation is a bit tricky for entities that are defined only by a stored procedure.
Navigating to these entities via navigation properties is not supported, since EF itself does not
support mapping functions for an entity to a query function (as it does for insert, update and
delete functions). You can of course define custom properties within your entities to perform
this navigation via a stored procedure query. Navigating from these stored-procedure backed
entities to table-backed entities is not a problem.
Query asynchronously
DevForce provides the ability to query asynchronously for two reasons:
1) The Silverlight CLR (common language runtime) environment does not permit
synchronous web service calls.
2) Even in those environments where synchronous API's are supported, there are many use
cases where performance can be improved via the use of an asynchonous query.
While an overview of asynchonous programming in DevForce discusses the specific
asynchronous API's provided in the context of querying. Please review the overview
document for context if necessary.
EntityQueryOperation<T> and EntityQueriedEventArgs<T>
The return value from any call to either a EntityQueryExtensions.ExecuteAsync or a
EntityManager.ExecuteQueryAsync is an instance of EntityQueryOperation<T>. This
operation result can be either be accessed directly within the method's callback logic or via
the operation's Completed event. In the case of the Completed event; the event delegate gets
passed a EntityQueriedEventArgs<T> parameter.
Regardless of whether you are working with an EntityQueryOperation<T> or an
EntityQueriedEventArgs<T>, the following read only properties are provided in addition to
those inherited from the BaseOperation or AsyncEventArgs base classes. Please see Program
asynchronously for more detail on the standard DevForce asynchronous model and the
properties available there. The following discussion is only about those additional properties
that are available during an asynchonous query.
Property Property Type Description
EntityQuery IEntityQuery<T> The requested query
Results IEnumerable<T> The results of the query.
ChangedEntities IList<Object>
The list of every entity that was either added or
modified in the EntityManager's cache as a result of this
query. The ChangedEntities list may differ from the
Results property since the Results will include only
those entities directly queried, and not entities fetched
due to query inversion or use of an "Include".
WasFetched bool
Whether the operation actually required a trip to the
database. Many queries can be completed without having
to go to the database.
ResolvedFetchStrategy FetchStrategy
The FetchStrategy actually used to process the query. This is
really only useful when an 'optimized' FetchStrategy was
stipulated when executing the query. What is returned here
is the query strategy that 'optimized' determined was most
appropriate.
Note that an exception is thrown when accessing the Results or ChangedEntities properties if the
asynchronous operation was either cancelled or failed, since the result is undefined.
Example of the ExecuteAsync() extension method and
EntityManager.ExecuteQueryAsync()
DevForce provides two primary ways to perform asynchronous queries. The first is to use any
of the ExecuteAsync() extension methods or EntityManager.ExecuteQueryAsync() method
overloads. For example:
C#
var query = _em1.Customers
.Where(c => c.ContactTitle == "Sales Representative")
.OrderBy(c => c.CompanyName);

// Using IEntityQuery.ExecuteAsync with lambda syntax:
query.ExecuteAsync( op => {
IEnumerable<Customer> customers = op.Results;
});

// Using EntityManager.ExecuteQueryAsync with lambda syntax:
_em1.ExecuteQueryAsync(query, op => {
IEnumerable<Customer> customers = op.Results;
});

// Using IEntityQuery.ExecuteAsync with Completed event syntax:
var op = query.ExecuteAsync();
op.Completed += (sender, eventArgs) => {
IEnumerable<Customer> customers = eventArgs.Results;
};

// Using EntityManager.ExecuteQueryAsync with Completed event syntax:
var op = _em1.ExecuteQueryAsync(query);
op.Completed += (sender, eventArgs) => {
IEnumerable<Customer> customers = eventArgs.Results;
};
VB
Dim query = _em1.Customers.Where(Function(c) c.ContactTitle = "Sales
Representative").OrderBy(Function(c) c.Compa

' Using IEntityQuery.ExecuteAsync with lambda syntax:
query.ExecuteAsync(Sub(op) Dim customers As IEnumerable(Of Customer) = op.Results)

' Using EntityManager.ExecuteQueryAsync with lambda syntax:
_em1.ExecuteQueryAsync(query, Sub(op) Dim customers As IEnumerable(Of Customer) =
op.Results)

' Using IEntityQuery.ExecuteAsync with Completed event syntax:
Dim op = query.ExecuteAsync()
AddHandler op.Completed, Sub(sender, eventArgs) Dim customers As IEnumerable(Of Customer)
= eventArgs.Results

' Using EntityManager.ExecuteQueryAsync with Completed event syntax:
Dim op = _em1.ExecuteQueryAsync(query)
AddHandler op.Completed, Sub(sender, eventArgs) Dim customers As IEnumerable(Of Customer)
= eventArgs.Results
Example of IEntityQuery.AsScalarAsync()
For what are termed "scalar queries", i.e. queries that return an immediate single result, the
mechanism is slightly different and uses the IEntityQuery.AsScalarAsync() extension method.
An example is shown below:
C#
var query = _em1.Customers
.Where(c => c.ContactTitle == "Sales Representative")
.OrderBy(c => c.CompanyName);

// Using lambda syntax
query.AsScalarAsync().FirstOrNullEntity( op => {
Customer cust = op.Result;
});

// Using Completed event syntax
var op = query.AsScalarAsync().FirstOrNullEntity();
op.Completed += (sender, eventArgs) => {
Customer cust = eventArgs.Result;
};
VB
Dim query = _em1.Customers.Where(Function(c) c.ContactTitle = _
"Sales Representative").OrderBy(Function(c) c.CompanyName)

' Using lambda syntax
query.AsScalarAsync().FirstOrNullEntity(Sub(op) Dim cust As Customer = op.Result)

' Using Completed event syntax
Dim op = query.AsScalarAsync().FirstOrNullEntity()
AddHandler op.Completed, Sub(sender, eventArgs) Dim cust As Customer = eventArgs.Result

Control query execution
What is a QueryStrategy?
QueryStrategy is a class in the IdeaBlade.EntityModel namespace. Every query has a
QueryStrategy property that returns a instance of the QueryStrategy type. This property has a
default value of null, but can be set on any query as follows:
C#
EntityQuery<Order> query01 = myEntityManager.Orders;
query01.QueryStrategy = QueryStrategy.DataSourceThenCache;
VB
Dim query01 As EntityQuery(Of Order) = myEntityManager.Orders
query01.QueryStrategy = QueryStrategy.DataSourceThenCache
In addition, every EntityManager has a DefaultQueryStrategy property that is used whenever
you do not explicitly specify the query strategy you want to use with a particular query. The
DefaultQueryStrategy is also used whenever you explicitly set a query's QueryStrategy
property to null (Nothing in VB). By default the DefaultQueryStrategy has a value of
QueryStrategy.Normal but you can also set it as follows:
C# myEntityManager.DefaultQueryStrategy = QueryStrategy.DataSourceOnly;
VB myEntityManager.DefaultQueryStrategy = QueryStrategy.DataSourceOnly
Entity navigation (e.g., myEmployee.Orders) is implemented with relation queries governed
by the DefaultQueryStrategy. In addition, any query whose QueryStrategy property has a
value of null will be executed with the DefaultQueryStrategy for the EntityManager under
which it is run.
The QueryStrategy class is immutable and has four properties that uniquely define it:

QueryStrategy.FetchStrategy
:The FetchStrategy controls where DevForce looks for the requested data: in the cache, in the
datasource, or in some combination of the two.

QueryStrategy.MergeStrategy
::The MergeStrategy controls how DevForce resolves conflicts between the states of objects
which, although already in the cache, are also retrieved from an external source.


QueryStrategy.InversionMode
:::The InversionMode controls whether DevForce attempts to retrieve objects that are
referenced in the query but are not the target type (e.g., the query give me all Customers
with Orders in the current year will return references to Customer objects, but must process
Order objects along the way).



QueryStrategy.TransactionSettings
::::The TransactionSettings object permits you to control the TimeOut and IsolationLevel
associated with a query, and also whether and how to use the Microsoft Distributed
Transaction Coordinator.

There are five static (Shared in VB) properties in the QueryStrategy class that return the five
most common combinations of a FetchStrategy, a MergeStrategy, and an InversionMode.
These will be named and discussed momentarily, but are much easier to understand after
examining the available FetchStrategy, MergeStrategy, and InversionMode options.
Pre-Defined QueryStrategies
Every QueryStrategy combines a FetchStrategy, a MergeStrategy, and a InversionMode.
Since there are five FetchStrategies, five MergeStrategies, and four InversionModes, there are
potentially 100 versions of QueryStrategy, even keeping the TransactionSettings constant.
However, in practice, a much smaller set of QueryStrategies suffices for the great majority of
purposes. DevForce has identified five of them as being of particular significance, enshrining
them as static (Shared in VB) properties of the QueryStrategy class. These pre-defined
QueryStrategies combine FetchStrategy, MergeStrategy, and InversionMode strategies as
shown in the table below:
Fetch and merge strategies of the common query strategies
QueryStrategy Fetch Strategy Merge Strategy InversionMode
Normal Optimized PreserveChanges Try
CacheOnly CacheOnly (Not Applicable) (Not Applicable)
DataSourceOnly DataSourceOnly OverwriteChanges Off
DataSourceOnlyWithInversion DataSourceOnly OverwriteChanges On
DataSourceThenCache DataSourceThenCache OverwriteChanges Try
Heres how you assign a pre-defined QueryStrategy:
C# query.QueryStrategy = QueryStrategy.DataSourceThenCache;
VB query.QueryStrategy = QueryStrategy.DataSourceThenCache
Custom QueryStrategies
As just noted, only five of the possible combinations of a FetchStrategy and a MergeStrategy
are covered by the named QueryStrategies. What if you want one of the other combinations?
You can create your own QueryStrategy by supplying the fetch and merge strategy
enumerations to its constructor. The result is a new immutable QueryStrategy instance.
Immutable meaning that we can get the component fetch and merge strategies but we cannot
reset them.
Heres an example of the creation and assignment of a custom QueryStrategy:
C#
QueryStrategy aQueryStrategy =
new QueryStrategy(FetchStrategy.DataSourceThenCache,
MergeStrategy.PreserveChanges,
QueryInversionMode.On);
VB
Dim aQueryStrategy As New QueryStrategy( _
FetchStrategy.DataSourceThenCache, _
MergeStrategy.PreserveChanges, _
QueryInversionMode.On)
There is another, often more useful, method of creating a custom QueryStrategy, via the use
of one of the With overloads provided by the QueryStrategy class. These With methods allow
you to create a new QueryStrategy based on an existing QueryStrategy with one of the
properties changed. For example:
C#
QueryStrategy queryStrategy1 = QueryStrategy.Normal.With(FetchStrategy.DataSourceOnly);
QueryStrategy queryStrategy2 =
QueryStrategy.DataSourceOnly.With(MergeStrategy.PreserveChangesUpdateOriginal);
QueryStrategy queryStrategy3 = queryStrategy1.With(QueryInversionMode.Off);
VB
Dim queryStrategy1 As QueryStrategy = _
QueryStrategy.Normal.With(FetchStrategy.DataSourceOnly)
Dim queryStrategy2 As QueryStrategy = _
QueryStrategy.DataSourceOnly.With(MergeStrategy.PreserveChangesUpdateOriginal)
Dim queryStrategy3 As QueryStrategy = _
queryStrategy1.With(QueryInversionMode.Off)
DefaultQueryStrategy
We mentioned earlier that the DevForce EntityManager has a DefaultQueryStrategy property
that can be used to shape the fetch and merge behavior of queries where the QueryStrategy is
not explicitly specified. The default setting for the EntityManagers DefaultQueryStrategy is
QueryStrategy.Normal. If you leave this setting at its default value, and in an individual query
do nothing to countermand the default settings, then the FetchStrategy of Optimized will be
used in combination with the MergeStrategy of PreserveChanges.
If for some reason you wanted a EntityManager where the default QueryStrategy would
always involve a trip to the data source, you could assign a different QueryStrategy, such as
DataSourceOnly, to the PMs DefaultQueryStrategy property. For a given query, you could
still use any desired QueryStrategy by explicitly specifying a different one.
When to use the different QueryStrategies
For most users, most of the time, the DevForce defaults are perfect:
Satisfy a query from the entity cache whenever possible;
When a trip to the data source is found necessary, resolve any conflicts that occur between
incoming data and data already cache by giving the local version priority; and
Perform query inversion as needed; if needed and undoable, revert to a DataSourceOnly
FetchStrategy.
Your choice of a non-default strategy can be driven by a variety of things. For example,
suppose your application supports online concert ticket sales. Your sales clerks need
absolutely up-to-date information about what seats are available at the time they make a sale.
In that use case, it will be essential to direct your query for available seats against the data
source, so a FetchStrategy of DataSourceOnly might be in order.
In code to handle concurrency conflicts, one might need a QueryStrategy with a
MergeStrategy of PreserveChangesUpdateOriginal to make an entity in conflict savable.
(The data source version of the conflicted entity would only be retrieved and used to partially
overwrite the cache version after the concurrency conflict had been resolved by some
predetermined strategy.)
You can and will think of your own reasons to use different combinations of FetchStrategy,
MergeStrategy, and InversionMode. Just ask yourself, for a given data retrieval operation,
whether the data in the cache is good enough, or you need absolutely current data from the
data source. Then ask yourself how you want to resolve conflicts between data already cached
and duplicate incoming data. Then consider the process DevForce will use to satisfy the query
and make sure it will have the data it needs to give you a correct result. DevForce gives you
the flexibility to set the behavior exactly as need it.
Changing a QueryStrategy for a single query execution
You may find yourself with an existing IEntityQuery object that you dont want to disturb in
any way, but which you would like to run with a different QueryStrategy for a specific, one-
time purpose. DevForce provides an extension method on IEntityQuery, called With(), that
permits you to this. ( Our topic here is QueryStrategy, but in fact some overloads of the
With() method also (or alternatively) permit you to make a one-time change to the
EntityManager against which the query will be run.) Note that this is a different method from
the QueryStrategy.With() method mentioned earlier.
When a call to With() is chained to a query, the result may be either a new query or a
reference to the original query. Normally it will be a new query, but if the content of the
With() call is such that the resultant query would be the same as the original one, a reference
to the original query is returned instead of a new query.
If you ever want to be sure that you get a new query, use the Clone() extension method
instead of With(). With() avoids the overhead of a Clone() when a copy is unnecessary.
C#
IEntityQuery<Customer> query00 = _em1.Customers
.Where(c => c.CompanyName.ToLower().StartsWith("a"));
query00.QueryStrategy = QueryStrategy.DataSourceOnly;
// The With() call in the right-hand side of the following statement
// specifies a query that is materially different from query0, in
// that it has a different QueryStrategy associated with it.
// Accordingly, the right-hand side of the statement will return
// a new query:
IEntityQuery<Customer> query01 =
query00.With(QueryStrategy.CacheOnly);
// Because the content of the With() call in the right-hand side
// of the following statement doesn't result in a modification
// of query0, the right-hand side will return a reference to
// query0 rather than a new query.
IEntityQuery<Customer> query02 =
query00.With(QueryStrategy.DataSourceOnly);
// If you want to be certain you get a new query, use Clone()
// rather than With():
EntityQuery<Customer> query03 =
(EntityQuery<Customer>)query00.Clone();
query03.QueryStrategy = QueryStrategy.DataSourceOnly;
VB
Dim query00 As IEntityQuery(Of Customer) = _
_em1.Customers.Where(Function(c) c.CompanyName.ToLower().StartsWith("a"))
query00.QueryStrategy = QueryStrategy.DataSourceOnly

' The With() call in the right-hand side of the following statement
' specifies a query that is materially different from query0, in
' that it has a different QueryStrategy associated with it.
' Accordingly, the right-hand side of the statement will return
' a new query:
Dim query01 As IEntityQuery(Of Customer) = _
query00.With(QueryStrategy.CacheOnly)

' Because the content of the With() call in the right-hand side
' of the following statement doesn't result in a modification
' of query0, the right-hand side will return a reference to
' query0 rather than a new query.
Dim query02 As IEntityQuery(Of Customer) = _
query00.With(QueryStrategy.DataSourceOnly)

' If you want to be certain you get a new query, use Clone()
' rather than With():
Dim query03 As EntityQuery(Of Customer) = _
CType(query00.Clone(), EntityQuery(Of Customer))
query03.QueryStrategy = QueryStrategy.DataSourceOnly
Control where the query executes
DevForce uses the FetchStrategy property of the QueryStrategy class to control where the
query executes: in the cache, in the datasource, or in some combination of the two.
FetchStrategies
Five FetchStrategies are available in DevForce:
Strategy Action
CacheOnly
Apply this query against the cache only, returning references only to entities
already there. Do not consult the data source. (Note that this query leaves
the cache unchanged.)
DataSourceOnly
Retrieve matching entries from the datasource into the entity cache. Return
references only to those entities retrieved from the the data source. A result
set returned from a query using this FetchStrategy would not include locally
added entities that had not yet been persisted to the data source.
DataSourceThenCache
First retrieve matching entries from the datasource into the entity cache.
Discard all references to entities retrieved in this step.
Resubmit the same query against the updated cache. Return references
only to entities matched by this second, CacheOnly query.
DataSourceAndCache
First retrieve matching entries from the datasource into the entity cache.
Retain references to entities retrieved in this step.
Resubmit the same query as CacheOnly. Combine (union) the
references obtained in this second, CacheOnly query with those
obtained in the data source retrieval step.
Optimized
Check the query cache to see if the current query has previously been
submitted (and, if necessary, inverted) successfully. If so, satisfy the
query from the entity cache, and skip the trip to the datasource.
If the query cache contains no query matching or encompassing the
current query, then determine if all entities needed to satisfy the query
correctly from the cache can be retrieved into the cache. If so, apply the
DataSourceThenCache FetchStrategy. Otherwise, apply the
DataSourceOnly FetchStrategy. See the discussion on query inversion
for more detail.
FetchStrategies when the client is disconnected from the data source
If the client is disconnected from the data source, the DataSourceOnly,
DataSourceThenCache, and DataSourceAndCache strategies will throw an
InvalidOperationException. The Optimized strategy will behave as a CacheOnly query. It will
not throw an exception, even if no matching query exists in the query cache.
Merge query results into the entity cache
DevForce uses a MergeStrategy to determine how to reconcile potential conflicts between
entities that are being merged into the cache with the entities that are already present in the
cache.
For example, you may have an existing version of an entity in the cache, and are trying to
merge with a "new" version of the same entity (the two entities have the same primary key).
This "new" entity may be the result of a query, a call to RefetchEntities, or may be an entity
that is being imported from another workflow using a different EntityManager. If one or both
entities have been changed, the MergeStrategy is used to determine which version of the
entity is stored in cache.
MergeStrategy
DevForce supports five different MergeStrategies : PreserveChanges, OverwriteChanges,
PreserveChangesUnlessOriginalObsolete, PreserveChangesUpdateOriginal, and
NotApplicable. Their meanings are shown in the table below.
When reviewing the table, remember that, for every cached DevForce entity, two states are
maintained: Original and Current . The Original state comprises the set of values for all
properties as they existed at the time of the last retrieval from, or save to, the datasource. The
Current state comprises the set of values for the objects properties as the end user sees them.
That is, the Current state values reflect any local changes that have been made since the entity
was retrieved, or last saved. When an entity is persisted, it is the values in its Current state
that are saved.
MergeStrategies:
Strategy Action when cached entity has pending changes
PreserveChanges Preserves the state of the cached entity.
OverwriteChanges
Overwrites the cached entity with data from the data source. Sets
the EntityState of the cached entity to Unchanged.
PreserveChangesUnless
OriginalObsolete
Preserves the values in the Current state of the cached entity,
if its Original state matches the state retrieved from the
datasource.
If the state as retrieved from the datasource differs from that
found locally in the Original set of property values, this
indicates that the entity has been changed externally by
another user or process. In this case (with this
MergeStrategy), DevForce overwrites the local entity, setting
the values in both its Current and Original states to match
that found in the datasource. DevForce also then sets the
EntityState of the cached instance to Unchanged.
PreserveChangesUpdateOriginal
Unconditionally preserves the values in the Current version for the
cached entity; and also updates the values in its Original version to
match the values in the instance retrieved from the datasource.
This has the effect of rendering the local entity savable (upon the
next attempt), when it might otherwise trigger a concurrency
exception.
NotApplicable
This merge strategy must be used and may only be used with
the CacheOnly fetch strategy. No merge action applies because no
data is retrieved from any source outside the cache.
MergeStrategy behavior
What happens during the merge of a data source entity and a cached entity depends upon the
answers to three crucial questions:
1. Is the entity current or obsolete?
2. How has it changed?
3. Is the entity represented in the data source?
Is the entity current or obsolete relative to the data source?
We compare the cached entitys concurrency column property value to that of its data source
entity. If the two are the same, the cached entity is current; if they differ, the cached entity is
obsolete.
As it happens, the cached entity has two concurrency column property values, a current one
and an original one. The value of the concurrency column in the current version is
meaningless. Its the value of the concurrency column in the original version that counts.
Every DevForce entity has an original version and a current version of its persistent state. We
can get to one or the other by means of a static GetValue() method defined on the
EntityProperty class. For example, the following code gets the original value (as retrieved
from the database) for the RequiredDate property of a particular Order instance:
C#
DomainModelEntityManager mgr = DomainModelEntityManager.DefaultManager;
anOrder = mgr.Orders.Where(o => o.OrderID == 10248).First();
Datetime reqdDate = Order.PropertyMetadata.RequiredDate.GetValue(
anOrder, EntityVersion.Current);
VB
DomainModelEntityManager.DefaultManager
anOrder = mgr.Orders.Where(Function(o) o.OrderID = 10248).First()
Dim reqdDate As Datetime = Order.PropertyMetadata.RequiredDate.GetValue(
anOrder, EntityVersion.Current)
Both of the following statements get the current value for the same property:
C#
reqdDate = Order.PropertyMetadata.RequiredDate.GetValue(
anOrder, EntityVersion.Current);

reqdDate = anOrder.RequiredDate; // same as above (but simpler!)
VB
reqdDate = Order.PropertyMetadata.RequiredDate.GetValue(anOrder, EntityVersion.Current)

reqdDate = anOrder.RequiredDate ' same as above (but simpler!)
Again, DevForce and the Entity Framework determine if our cached entity is current or
obsolete based on the original version of the property value.
How has it changed?
The merge action depends upon whether the entity was added, deleted, or changed since we
set its original version. The entitys EntityState property tells us if and how it has changed.
Is the entity represented in the data source?
If there is a data source entity that corresponds to the cached entity, we may use the data from
data source entity to change the cached entity in some way.
If we dont find a matching data source entity, we have to decide what to do with the cached
entity. Maybe someone deleted the data source entity in which case we might want to discard
the cached entity. If we, on the other hand, we want to save the cached entity, well have to
insert it into the data source rather than update the data source.
Merging when the entity is in the data source
Well look at each strategy and describe the outcome based on (a) whether or not the cached
entity is current and (b) the entitys EntityState.
If the entity is Unchanged, we always replace both its original and current versions with data
from the data source entity.
Our remaining choices are evident in the following table.
Merge strategy consequences for a changed cached entity that exists in the data source.
Merge Strategy Current Added Deleted Detached Modified
Post
Current
PreserveChanges Y NC NC NC NC Y
N NC NC NC NC N
OverwriteChanges Y or N OW OW OW OW Y
PreserveChangesUnless
OriginalObsolete
Y ---- NC NC NC Y
N OW OW OW OW Y
PreserveChangesUpdateOriginal Y or N NC NC NC NC Y
NC = No change; preserve the current version values of the cached entity
OW = Overwrite the cached entitys current version values with data from the data source
entity
Post Current = Y means the cached entity is current relative to the data source after the
merge.
There are important artifacts not immediately observable from this table.
The entitys EntityState may change after the merge. It will be marked Unmodified after
merge with OverwriteChanges. It will be marked Unmodified after merge with
PreserveChangesUnlessOriginalObsolete if the entity is obsolete.
Note that deleted and detached entities are resurrected in both cases.
An added cached entity must be deemed obsolete if it already exists in the data source. The
entity exists in the data source if the query returns an object with a matching primary key. If
we think we created Employee with Id=3 and we fetch one with Id=3, someone beat us to it
and used up that Id value. Our entity is obsolete. We will not be able to insert that entity into
the data source; well have to update the data source instead.
The PreserveChangesUpdateOriginal strategy enables us to force our changes into the data
source even if the entity is obsolete. An added entity merged with
PreserveChangesUpdateOriginal will be marked Modified so that DevForce knows to update
the data source when saving it.
These effects are summarized in the following table:
EntityState after merge.
Merge Strategy Current Added Deleted Detached Modified
PreserveChanges Y or N A D Dt M
OverwriteChanges Y or N U U U U
PreserveChangesUnless
OriginalObsolete
Y --- D Dt M
N U U U U
PreserveChangesUpdateOriginal Y or N M D Dt M
A = Added
D = Deleted
Dt = Detached
M = Modified
U = Unchanged
The merge may change the original version of a changed cached entity to match the data
source values.
PreserveChanges never touches the original version.
The original version is always changed with the OverwriteChanges strategy.
It is reset with the PreserveChangesUnlessOriginalObsolete strategy if (and only if) the entity
is obsolete..
PreserveChangesUpdateOriginal updates the original version (but not the current version!) if
the entity is obsolete. This step ensures that the cached entity appears current while
preserving the pending changes.
These effects are summarized in the following table:
Merge strategy effect on the original version of the cashed entity.
Merge Strategy Current Adde