Sei sulla pagina 1di 759

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 Added Deleted Detached Modified
PreserveChanges Y or N NC NC NC NC
OverwriteChanges Y or N OW OW OW OW
PreserveChangesUnless
OriginalObsolete
Y ---- NC NC NC
N OW OW OW OW
PreserveChangesUpdateOriginal Y or N OW OW OW OW
Merging when the cached entity is not in the data source
We begin by considering cached entities that are unchanged. If the query applied to the cache
returns an unchanged entity, X, and the query applied to the data source did not return its
mate, we can safely assume that X was deleted after we fetched it. We can remove X from
the cache.
We turn next to changed cached entities where we must distinguish between a query that tests
only for the primary key and one that tests for something other than the primary key.
If the query tests for anything other than the primary key, we can draw no conclusions from
the fact that a cached entity was not found in the database. For what does it mean if we have
an employee named "Sue" in cache and we dont find her in the data source? Perhaps
someone deleted her from the data source. Maybe someone merely renamed her. Maybe we
renamed her. The combinations are too many to ponder.
On the other hand, if we query for Employee with Id = 3 and we dont find that employee in
the data source, we can be confident of a simple interpretation. DevForce confirms that the
primary key has not changed. While it is good practice to use immutable keys, it is not always
so. If the primary key has been changed, DevForce leaves the cached entity alone. A business
object must have unique identity so if it isnt there, either it was never there or it has been
deleted. What happens next depends upon the EntityState of the cached entity and the merge
strategy.
DevForce recovers gracefully when it attempts to save an entity marked for deletion and it
cant find the data source entity to delete so the merge can leave this cached entity alone. It
can also skip over the detached entities.
PreserveChanges forbids merge effects on changed entities. The entity stays put in the cache.
OverwriteChanges takes the data source as gospel. If the cached entitys EntityState is
Modified, there should be an existing data source entity. There is not, so DevForce assumes
the data source entity has been deleted and the cache should catch up with this reality. It
removes the entity from the cache. Removal from the cache is just that. The entity
disappears from cache and will not factor in a save. It does not mean delete which requires
DevForce to try to delete the entity from the data source. It is an action neutral to the data
source.

On the other hand, if the cached entity is new (Added), we dont expect it to be in the data
source. The entity remains as is in the cache, a candidate for insertion into the data source.
PreserveChangesUnlessOriginalObsolete behaves just like OverwriteChanges.
PreserveChangesUpdateOriginal strives to position the entity for a successful save. It must
intervene to enable data source insertion of a modified entity by changing its EntityState to
Added. An update would fail because there is no data source entity to update.
In summary:
Merge strategy consequences for a changed cached entity that does not exist in the data
source.
Merge Strategy Added Modified
PreserveChanges A M
OverwriteChanges A R
PreserveChangesUnlessOriginalObsolete A R
PreserveChangesUpdateOriginal A A
A = Added
M = Modified
R = Removed
DataSourceOnly subtleties
We may get a nasty surprise if we use a DataSourceOnly or DataSourceThenCache query
with other than the OverwriteChanges merge strategy. Consider the following queries using
the PreserveChanges merge strategy.
Suppose we hold the "Nancy" employee in cache. We change her name to "Sue" and then
search the database for all Employees with first names beginning with S. We will not get
"Sue" because she is still "Nancy" in the database.
Suppose we search again but this time we search for first names beginning with N. This time we get
"Sue". That will confuse the end user but it is technically correct because the Sue in cache is still
"Nancy" in the database. DataSourceThenCache will produce the same anomaly for the same reason:
the database query picks up the object in the database as "Nancy" but preserves the modification in
cache which shows her as "Sue".



Invert a query
Inverting a query is accomplished through query inversion. Query inversion conveys a
process by which we try to insure that any data queried from a backend datasource can also be
queried, with the same results, by executing the same query against the local entity
cache. This is difficult to insure under two conditions
1. Where a query involves a projection. ( Select or SelectMany)
2. Where a query involves a subquery.
InversionMode
DevForce is able to automatically perform query inversion on queries that involve subqueries,
but must rely on the developer's assistance in inverting projection queries via judicious use of
Include clauses. Because of this it is often useful to construct queries using subqueries instead
of projections in order to gain access to DevForce's automatic query inversion logic.
An example of query inversion follows:
The query "get me all Customers with Orders in the current year" will return references to
Customer objects, but must first examine many Order objects in order to return the correct set
of Customers. The query "give me the count of Customers located in Idaho" will return an
integer, but must examine the Customer collection in the data source.
Query inversion is the process of retrieving those non-targeted objects that are nonetheless
necessary for correct completion of a query. The most fundamental reason for doing query
inversion is so that the query can be applied against a pool of data that combines unpersisted
local data with data that exists in the datasource. This is, after all, what your end user
normally wants: query results based on the state of the data as she has modified it.
The only place that combined pool of data can exist, prior to persisting changes, is the local
cache. Therefore the query must ultimately be applied against the cache; and that operation, if
it is to return correct results, requires the cache to contain all entities that must be examined in
the course of satisfying the query. So to satisfy the query "get me all Customers with Orders
in the current year", the cache must contain not only the Customers to which references will
be returned, but also all of the current-year Orders that were placed by these customers.
Another way of understanding the idea of inverting queries is that the same query, if
resubmitted during the same application session, can be satisfied entirely from the cache,
without requiring another trip to the datasource.
A handy side effect of query inversion is that in practice there is a reasonably good chance
that the related objects needed for satisfaction of the query will also be referenced in other
ways by the application. In this very common scenario, the effect of the extra data retrieved is
to improve client-side performance by eliminating the need for separate retrieval of the related
objects.
Note that the end result of a query inversion process is very similar to that which occurs when
the .Include() method is used in a query. Both processes result in the retrieval and local
storage of objects that are related to a set of root objects that are the primary target of a
particular query.
Four InversionModes are available in DevForce for a query:
Inversion
Mode
Implicit Instructions to DevForce
On
Attempt to retrieve, from the datasource and into the cache, entities other than the
targeted type which are needed for correct processing of the query. If this attempt fails,
throw an exception.
Off Do not attempt to retrieve entities other than the targeted type into the cache.
Try
Attempt to retrieve, from the datasource and into the cache, all entities other than the
targeted type which are needed for correct processing of the query. However, if this
attempt fails, just retrieve the entities of the directly targeted type, and do not throw an
exception.
Manual
Dont attempt to invert the current query; but act as if it were successfully inverted
(if it needed to be).
You (the developer) should only use this InversionMode when you are prepared to
guarantee, on your own, that the entity cache contains (or will contain, after the
DataSource portion of the query operation) all the necessary related objects to return
a correct result if submitted against the cache. Normally you would make good on
this guarantee by performing other data retrieval operations (prior to the one in
question) to retrieve the necessary related data; or by including calls to the Include()
extension method in the current query, sufficient to retrieve the necessary related
data.
The default InversionMode is Try, and this will likely be your choice for most queries.
You should use On only if your application absolutely depends upon the related entities being
brought into the cache by your query, and you should include exception handling in case the
strategy fails.
Choose the Off setting if you only want the targeted entries retrieved into the cache. Be sure
you choose a compatible FetchStrategy.
For queries that DevForce can successfully invert, the InversionModes of Try and On will
yield the same end state: the query will be cached, and all related objects necessary to permit
future satisfaction of the query entirely from the cache will be assumed to be present in the
cache. If you use the InversionMode of Manual properly that is, you take care to see that the
necessary related objects get retrieved into the cache by some means or another before the
query is submitted then it, too, will produce the same ending state as the Try and On
settings.
Queries that cannot be automatically inverted
The following types of queries cannot be automatically inverted:
A query that returns a scalar result. This includes all aggregate queries (Count, Sum, Avg,
etc.). Note that this group includes the example mentioned earlier in this discussion: Give
me the count of Customers located in Idaho.
C# var query02 = _em1.Orders.Select(o => o.FreightCost).Sum();
VB Dim query02 = _em1.Orders.Select(Function(o) o.FreightCost).Sum()
A query whose return type is a single element. These include queries that call .First(), .Last(),
and .Single()
C# var query03 = _em1.Products.OrderByDescending(c =>
c.ProductName).FirstOrNullEntity();
{{/code}}
VB
Dim query03 = _em1.Products.OrderByDescending( _
Function(c) c.ProductName).FirstOrNullEntity()
A query whose return type is different from the type contained in the collection first
referenced.
C#
var query04 = _em1.Customers
.Where(c => c.Country == "Argentina")
.SelectMany(c => c.Orders);
VB
Dim query04 = _em1.Customers _
.Where(Function(c) c.Country = "Argentina") _
.SelectMany(Function(c) c.Orders)
Match the semantics of cache queries to database queries
There are several interesting issues that arise when DevForce tries to execute the same
EntityQuery against both a backend datastore using the Entity Framework and its own local
EntityManager cache. Internally DevForce uses LINQ to Entities to query entities on the
server but uses LINQ to Objects (LINQ against the .NET CLR) to query these same entities
from the local cache. Unfortunately, there are subtle semantic differences between LINQ to
Entities and LINQ to Objects. Some of these differences have to do with the way that LINQ
to Entities itself is defined and some of these differences have to do with the backend SQL
database implementation that LINQ to Entities is communicating with. Ideally we want to
match the semantics of cache queries to database queries.
QueryStrategy and CacheQueryOptions
In general, it is DevForce's goal to insure that the execution of a query against the local
EntityManager cache is interpreted identically to that same query run against Linq to Entities
on the server. This is accomplished by modifying the way that standard LINQ to Objects
queries are interpreted when run against the DevForce EntityManager cache. The goal is to
mirror LINQ to Entities semantics for these queries. While much of this can be performed
automatically by DevForce, there is some logic that is dependent on the settings of whatever
backend SQL database is being used on the server.
The IdeaBlade.EntityModel.CacheQueryOptions property contains the settings that allow a
developer to inform DevForce of any database settings that may effect LINQ to Entities
behavior, and that will therefore require DevForce to modify the way it executes those same
queries when run against the local cache as well. Typically, within a single application, these
settings will be the same for all queries and therefore the CacheQueryOptions class offers a
static (shared in VB) 'Default' property that will be used by every query unless explicitly
overridden on that query's QueryStrategy. By default this property returns an instance of
CacheQueryOptions that is appropriate for most standard SQL Server implementations. (See
CacheQueryOptions.DefaultSqlServerCompatibility)
Instances of the CacheQueryOptions class are immutable and can be created via the following
constructor
C#
public CacheQueryOptions(StringComparison stringComparison,
bool useSql92CompliantStringComparison, GuidOrdering guidOrdering)
VB
public CacheQueryOptions(StringComparison stringComparison, _
Boolean useSql92CompliantStringComparison, GuidOrdering guidOrdering)
Each of the parameters to the constructor is described below:
stringComparison: Because many SQL databases are configured to allow queries against
string columns to be performed in a case insensitive manner, it is necessary to inform
DevForce that it should mirror this behavior when performing queries against its local cache.
Note that this is different than standard Linq to Objects (.NET CLR behavior) which is to
perform case sensitive comparisons. The default for this is
StringComparison.OrdinalIgnoreCase. (i.e. case insensitive comparisons).
useSql92CompliantStringComparison: The ANSI/ISO SQL-92 specification (Section 8.2,
<Comparison Predicate>, General rules #3) describes how to compare strings with spaces.
The ANSI standard requires padding for the character strings used in comparisons so that
their lengths match before comparing them. The padding directly affects the semantics of
WHERE and HAVING clause predicates and other string comparisons. For example, ANSI-
SQL considers the strings 'abc' and 'abc ' to be equivalent for most comparison
operations. This is the behavior that DevForce mimics for local cache queries when this value
is set to true, otherwise normal .NET CLR comparison semantics are used (i.e. no padding).
The default value for this flag is true.
guidOrdering: SQL Server currently sorts 'Guids' according to different rules than those used
by the .NET CLR. This setting allows the local cache to match SQL Server's sorting behavior
in any LINQ query that involves grouping or ordering of 'Guid's. The default for this property
is GuidOrdering.SqlServer. The only other option currently available is GuidOrdering.CLR.
Transactional queries
DevForce query requests are atomic. This means that even when a query request resolves into
multiple SQL queries, they will all be performed together within the same transaction.
Individual query requests resolve into several SQL queries when the query has includes that
fetch related objects or when the query involves one or more sub-queries and query inversion
is turned on.
When the root query is performed transactionally, both the main select and the selection of
related entities occur within transactional boundaries.
Setting the transaction isolation level on individual commands
Developers can set the transaction isolation level for individual queries and saves.
There is a TransactionSettings class and a TransactionSettings property on the QueryStrategy
class.
The TransactionSettings class provides the ability to dynamically set:
The Transaction Isolation level of a Query (or Save)
The Transaction Timeout to be applied to a Query (or Save)
Note: The Default Transaction Isolation Level when you create the TransactionSettings
object is ReadCommitted. This is not always the most performant choice, so be sure to
research the isolation level appropriate for your application.
Cache a query
Last modified on March 23, 2011 22:52
Contents
Query Cache
Removing an entity clears the query cache
Cache use when disconnected
Modifications
Stale entity data
The DevForce EntityManager maintains two caches that you can use to cache a query.
An entity cache that contains every entity that gets added to an EntityManager regardless of
how those entities are retrieved or created.
A query cache that contains every query that has been processed against a backend
datastore that satisfies a specific set of criteria described later in this section.
The rules by which a query's results are processed into the EntityManager cache in
determined by a query strategy. When following the default, normal strategy, the EM tries
first to satisfy a query from data in its cache; it reaches out to the data source only if it must.


Query Cache
When a EntityManager begins to process a normal query, it checks its query cache to see if it
has processed this exact query before. This query cache is available for programatic
manipulation via the an EntityManager's QueryCache property.
If the EntityManager finds the query in the query cache, it assumes that the objects which
satisfy the query are in the entity cache; accordingly, it satisfies the query entirely from the
entity cache without consulting the data source.
A one-to-many entity navigation, such as from employee to the employees orders, is
translated implicitly to an IEntityQuery instance that also enters the query cache. The next
time the application navigates from that same employee to its orders, the EntityManager will
recognize that it has performed the query before and look only in the cache for those orders.
The query cache grows during the course of a session. Certain operations clear it as one of
their side-effects; removing an entity from the cache is one such operation. The developer can
also clear the query cache explicitly, or add queries to the cache that he or she knows can be
satisfied from the cache.
DevForce caches queries to improve performance. This analysis applies to both entity queries
and entity navigation. Both use Optimized fetch strategy by default. Consider a query for
employees with FirstName = "Nancy". The QueryStrategy is Normal which means the fetch
strategy is Optimized, which means that the retrieval will be from cache when possible.
When we execute this query in an empty EntityManager, there will be a trip across the
network to fetch the entities from the data source. We get back "Nancy Davolio" and "Nancy
Sinatra". If we execute the query again, the EntityManager satisfies the query from the entity
cache and returns the same result; it does not seek data from the data source.
During the first run the EntityManager stored the query in its Query Cache. The
EntityManager stores the query in the query cache when (a) the query is successful, (b) it
searched the data source (not just the cache), and c) the query is invertible. The second time it
found the query in the Query Cache and thus knew it could apply the cache to the query
instead.
If we change "Nancy Davolio" to "Sue" and run the query again, we get back just "Nancy
Sinatra". If we change "Sally Wilson" to "Nancy Wilson" and run it again, well get the
principals of a strange duet. So far, everything is working fine.
Meanwhile, another user saves "Nancy Ajram" to the data source. We run our query again and
we still have just a duet. The EntityManager didnt go to the data source so it doesnt find
the Lebanese pop star.
Such behavior may be just fine for this application. If it is not, the developer has choices. She
can:
Use a QueryStrategy with a different FetchStrategy that looks at the database first.
Clear the query cache explicitly by calling EntityManager.QueryCache Clear method.
Clear the query cache implicitly by removing any entity from the entity cache.
Removing an entity clears the query cache
When we remove an entity from an EntityManagers entity cache ( via the RemoveEntity or
RemoveEntities methods), DevForce automatically clears the entire query cache for the
EntityManager.
Thats right it erases the EntityManagers memory of all* the queries it has performed.
Note that we are NOT talking about deleting an entity here. Deletion does not cause a
clearing of the query cache.
Suppose we frequently query for employees hired this year. If we issue this query twice, the
first query fetches the employees from the database; the second retrieves them from the cache.
The second query is almost instantaneous.
Then we remove an unrelated entity such as a Customer or an Address. We query again.
Instead of reading from the cache as it did before, the EntityManager goes back to the
database for these employees.
Seems unfair, doesnt it? But its the safe thing to do.
If we issue the same query multiple times, we expect the same results every time. We expect a
different result only if data relevant to our query have changed.
The EntityManager will search the local cache instead of the database only if it "believes" that
all essential information necessary to perform the query are resident in the cache. If it "thinks"
that the cache has been compromised, it should go back to the data source to satisfy the query.
Removing an entity compromises the cache. For sure it invalidates at least one query the
query that fetched it in the first place. But is that the only invalidated query? The
EntityManager does not know. So it does the safe thing and forgets all queries.
You and I know (or we think we know) that removing a Customer or Address has no bearing
on employees hired this year. The EntityManager is not so sure.
There are circumstances when (a) we have to remove an entity and (b) we are certain that no
queries will be adversely affected. For example, our query may return entities which weve
marked as inactive. We never want inactive entities in our cache but, for reasons we need not
explain here, we have inactive entities in the cache.
We want to remove those entities. Being inactive they cannot possibly contribute to a correct
query result.
Unfortunately, removing those entities clears the entire query cache. The EntityManager will
satisfy future queries from the database until it has rebuilt its query cache.
This is not a problem if we rarely have to purge inactive entities. But what if we have to purge
them after almost every query?. (This is not a rare scenario.) We will never have a query
cache and we will always search the database. The performance of our application will
degrade.
Fortunately, there is a RemoveEntities signature that can remove entities without clearing the
query cache. In the full knowledge of the risk involved, we can call
EntityManager.RemoveEntities(entitiesToRemove, false)
The false parameter tells the EntityManager that is should not clear the query cache.
Remember: removing an entity and deleting it are different operations. Removing it
from the cache erases it from client memory; it says nothing about whether or not the
entity should be deleted from its permanent home in remote storage. Delete, on the
other hand, is a command to expunge the entity from permanent storage. The
deleted entity stays in cache until the program can erase it from permanent storage.
Cache use when disconnected
When the EntityManager is in the disconnected state, it will satisfy a navigation, or a query
submitted with the Normal QueryStrategy, from the entity cache alone; it will not attempt to
search the data source. The EntityManager raises an exception if it discovers during query
processing that it cant reach the data source and a query strategy has been specified that
requires that the data source be accessed. See Take offline to learn more about disconnected
operations.
Modifications
Each business object carries a read-only EntityState property that indicates if the object is
new, modified, marked for deletion, or unchanged since it was last retrieved.
It bears repeating that our local modifications affect only the cached copy of a business
object, not its version in the data source. The data source version wont be updated until the
application tells the EntityManager to save the changed object.
It follows that the data source version can differ from our cached copy either because we
modified the cached copy or because another user saved a different version to the data source
after we retrieved our copy.
It would be annoying at best if the EntityManager overwrote our local changes each time it
queried the data source. Fortunately, in a normal query, the EntityManager will only replace
an unmodified version of an object already in the cache; our modified objects are preserved
until we save or undo them.
Stale entity data
All of this is convenient. But what if another user has made changes to a cached entity? The
local application is referencing the cached version and is unaware of the revisions. For the
remainder of the user session, the application will be using out-of-date data.
The developer must choose how to cope with this possibility. Delayed recognition of non-
local changes is often acceptable. A list of U.S. States or zip codes is unlikely to change
during a user session. Employee name changes may be too infrequent and generally harmless
to worry about. In such circumstances the default caching and query behavior is fine.
If concurrency checking is enabled and the user tries to save a changed object to the
data source, DevForce will detect the collision with the previously modified version in
the data source. The update will fail and DevForce will report this failure to the
application which can take steps to resolve it.
Some objects are so volatile and critical that the application must be alert to external changes.
The developer can implement alternative approaches to maintaining entity currency by
invoking optional DevForce facilities for managing cached objects and forcing queries that go
to the data source and merge the results back into the cache.
The facilities for this are detailed in the Query Strategy section.

Secure the query with attributes
The server should only honor a query coming from a client if the client is properly authorized.
The EntityServerQueryInterceptor is the most flexible way to evaluate and authorize a query
but it requires code. You may be able to satisfy your query security requirements
declaritively by adding security attributes either to the entity type or to named query
methods. This topic explains what those attributes are and how they work.


Security attributes
Security attributes are the easiest way to authorize client queries. You can add attributes to
entity class definitions and to named query methods.
Here is a table summarizing query security attributes, followed by an explanation of how to
add them, what they do, and when DevForce applies them.
Attribute Summary
ClientQueryPermissions
Enable or disable the client's right to use certain query features such
Include clauses and projections (Select clauses).
RequiresAuthentication
Whether client must be authenticated to execute this named query or refer
to the adorned entity type in a query.
RequiresRoles
Which client roles are required in order to execute this named query or
refer to the adorned entity type in a query.
ClientCanQuery
Whether the client can refer to this type in a query. This attribute can be
applied to an entity type but not to a named query method.
ClientQueryPermissions
The ClientQueryPermissions attribute enables (or disables) certain query features. At the
moment it controls two client query features:
1. Include clauses: an Include clause adds related entities to query results.
2. Projections: a "projection" is a query that uses the Select or SelectMany LINQ operation to
change the type of the result.
The attribute specifies a flag enumeration, ClientQueryPermissions, that captures the
permission combinations. The enum values are:
Minimal (no Includes, no projections)
AllowIncludes
AllowProjections
All (allow both includes, and projections)
You can apply this attribute to an entity type or to a named query method. Here is an example
of the attribute applied to the Orders type.
C#
[ClientQueryPermissions(ClientQueryPermissions.AllowProjections)]
public partial class Order{...}
VB
<ClientQueryPermissions(ClientQueryPermissions.AllowProjections)>
Partial Public Class Order ...
When both the entity type and a named query method have conflicting attributes, the named
query attribute takes precedence.
You can associate this attribute with specific user roles and you can apply the attribute several
times in order to express different permissions for different roles. In the following
GetGoldCustomers named query example, administrators can use Includes and Projections
with this query but no one else can:
C#
[ClientQueryPermissions(ClientQueryPermissions.All, "admin")]
[ClientQueryPermissions(ClientQueryPermissions.Minimal)]
public IQueryable<Customer> GetGoldCustomers() {...}
VB
<ClientQueryPermissions(ClientQueryPermissions.All, "admin")> _
<ClientQueryPermissions(ClientQueryPermissions.Minimal)> _
Public Function GetGoldCustomers() As IQueryable(Of Customer) ...
This attribute is beta as of version 6.1.0. A known issue causes DevForce to improperly apply
this attribute to LINQ statements returned by a named query.
RequiresAuthorization and RequiresRoles
These two attributes serve the same purpose as the like-named WCF RIA Services attributes.
RequiresAuthentication ensures that a user must be authenticated to query the entity or use
the named query method.
RequiresRoles ensures that only users with specific roles can query the entity or use the
named query method.
The EntityServerSaveInterceptor uses these same attributes to determine if the client is
authorized to save the entity type.

ClientCanQuery
The ClientCanQuery attribute is similar to the RequiresRoles attribute but there are
differences. You can only apply the ClientCanQuery to entity types, not named queries. It
offers a little more precision when specifying which kinds of users can reference an entity
type in a query.
Example Effect
ClientCanQuery(false) No user can query with the type
ClientCanQuery(true) All users can query with the type
ClientCanQuery(AuthorizeRolesMode.Any, role1,
role2 ...)
A user with any of the mentioned roles can
query with the type.
ClientCanQuery(AuthorizeRolesMode.All, role1,
role2 ...)
Only a user with all of the mentioned roles can
query with the type.
ClientCanQuery is true by default so you generally do not need to add this attribute to your
entity classes. However, you can reverse the default (see the discussion of
DefaultAuthorization below) which would mean that, by default, no client could query with
this type. If you change the default in this way, you may want to add this attribute to those
types which should be client queryable and set it to true explicitly.
The ClientCanQuery attribute is evaluated after RequiresAuthentication and RequiresRoles.
Add attributes to entity types in the EDM Designer
When you created your entity model, you may have noticed in the EDM Designer that each
Entity has DevForce properties that govern the ability of the client to query and save:

The CanQuery property translates to the ClientCanQuery attribute on the generated entity
class. The "Allow includes" and "Allow projections" properties combine to determine a
ClientQueryPermissions attribute on the generated entity class.
The property values are tri-state: True, False, and Default. "Default" means "rely on the
EntityServerQueryInterceptor's default" as described below and DevForce won't generate the
corresponding attribute. Because the "Allow ..." properties resolve to a single attribute; either
both are "default" or neither is.
Suppose we kept the default values for the two "Allow ..." properties and disabled (made
false) the client's ability to query this type. The generated class would look like this:
C#
[IbEm.ClientCanQuery(false)]
public partial class OrderDetail : IbEm.Entity {}
VB
<IbEm.ClientCanQuery(False)>
Partial Public Class OrderDetail
Inherits IbEm.Entity
End Class
Turning off all direct query access may seem a bit draconian, but this is a valid approach for
those types that you really only want to allow on the server.
Add attributes to the entity partial class
You don't have to rely on the EDM designer to generate the attributes. You can add them to
the entity's partial class where you can be more particular and assign permissions by role as
seen in this example.
C#
[ClientCanQuery(AuthorizeRolesMode.Any, "Admin", "Sales")]
public partial class Order : IbEm.Entity {}
VB
<ClientCanQuery(AuthorizeRolesMode.Any, "Admin", "Sales")>
Partial Public Class Order
Inherits IbEm.Entity
End Class
You'll need the partial class if you want to add the RequiresAuthentication or RequiresRoles
attributes.
C#
[RequiresAuthentication]
public partial class OrderDetail : IbEm.Entity {}
VB
<RequiresAuthentication>
Partial Public Class OrderDetail
Inherits IbEm.Entity
End Class
Add attributes to named query methods
You can add any of the query security attributes to the definition of a named query method
except ClientCanQuery. Here's and example restricting a specialized named query to
adminstrators
C#
[RequiresRoles("admin")]
public IQueryable<Customer> GetGoldCustomers() {...}
VB
<RequiresRoles("admin")>
Public Function GetGoldCustomers() As IQueryable(Of Customer)...
Attributes and the EntityServerQueryInterceptor
The security attributes don't do anything on their own. They are metadata to be read and
interpreted. Your code can read the metadata, perhaps to control the appearance and
capabilities of the UI.
The DevForce EntityServerQueryInterceptor reads and interprets the metadata when it
processes the query. You can derive from this class and override virtual methods to introduce
custom logic of your own including custom query security logic.
EntityServerQueryInterceptor.AuthorizeQuery is the primary method to override. This
method first calls GetClientQueryPermission to confirm that the client query is only using
permitted features. Then it calls the ClientCanQuery method for each entity type involved in
the original client query in order to verify that the client is authorized to refer to that type in a
query. The default ClientCanQuery method discovers and applies the following attributes in
sequence:
RequiresAuthentication
RequiresRoles
ClientCanQuery
It bears repeating that this phase of the analysis applies to the original client query, not the
named query.
Types specified inside the named query get a free pass. For example, you can prevent client
queries from using the Customer type by setting ClientCanQuery to false. If a client submitted
a query for Customers, the server would reject it. But it is OK for the client to invoke the
GetGoldCustomers named query even though its implementation involves the Customer type;
a named query is written for and executed on the server and is presumed to be secure.
Types appearing in Include clauses are checked as well
For example, suppose you blocked query of the OrderDetails type by adorning that class with
ClientCanQuery(false). The client could not query for OrderDetails directly. The client would
also be unable to acquire OrderDetail entities indirectly via a query for Orders that had an
"OrderDetails" Include clause.
Defaults in the absence of attributes
The default GetClientQueryPermission method looks for a ClientQueryPermissions attribute
for the query. If it can't find that attribute, it substitutes the DefaultClientQueryPermissions.
The default is "All" meaning that all potential client query features are permitted. You can
override this property to provide a more restrictive global setting such as "Minimal". Then the
developer would have to enable query features explicitly on either the entity types or named
query methods.
The ClientCanQuery method looks for a ClientCanQuery attribute on each type involved in
the client query. If it can't find that attribute, it allows or disallows the query based on the
value of the DefaultAuthorization property. That value is true by default, meaning that a type
without a ClientCanQuery attribute can be queried. You can reverse this default by overriding
this property and returning false; then every type must carry the ClientCanQuery attribute or
it can't be referenced in a client query.
Summary of virtual authorization interception members
The following Authorization-related properties and methods are all virtual which means that
you can override them in your custom derived EntityServerQueryInterceptor.
Member Summary
AuthorizeQuery
The primary query authorization method; it orchestrates
authorization and calls the other authorization members.
GetClientQueryPermissions Get the permissions that govern certain query features.
DefaultClientQueryPermissions
Get the ClientQueryPermissions enum to use when no attribute is
specified.
ClientCanQuery Get whether the client can refer to the specified type in this query.
DefaultAuthorization
Get whether the type can be referenced in a query if it lacks a
ClientCanQuery attribute.
You typically delegate to DevForce base class members, either before or after running your
code ... but you don't have to do so. For example, within the interceptor you could ignore
DevForce's interpretation of the attributes when you have better, perhaps contradicting,
information available to you.
EntityServerQueryInterceptor and named queries
When the client submits a query that invokes a named query, DevForce authorizes the named
query first. You cannot bypass the RequiresAuthentication and RequiresRoles attributes that
adorn a named query method. If the named query fails attributed authorization, the query fails
before reaching the EntityServerQueryInterceptor.
If the named query survives these attribute-based security checks, DevForce combines the
output of the named query method with the original client query instructions and passes the
product of that combination to the EntityServerQueryInterceptor.
The interceptor has access to the original client query and the original named query method as
described here which means you can analyze the parts in your own custom interceptor.
Query lifecycle
Last modified on March 23, 2011 22:54
When DevForce executes a standard query, a sequence of steps is followed that involves code
executing both on the client where the query was submitted as well as on the EntityServer
where, in most cases, a backend datastore resides. This sequence, the query lifecycle, can be
intercepted by the developer on both the client and the server, via a variety of mechanisms.
A workflow
The table below shows the lifecycle of a query assuming a QueryStrategy of Normal.
Table 1. Entity Query and Navigation Workflow When QueryStrategy = Normal
Component Action
Client Tier
Application
Code
1) The client application requests a particular set of entities (the desired entities)
either by entity query or by entity navigation
Client Tier
2) The EntityManager raises a Querying event. Listeners can see the query
EntityManager and, optionally, cancel the query.
3) The EntityManager checks the QueryCache (and sometimes the
EntityCache depending on the kind of query) to see if it can satisfy the query
with the entities in the client-side cache. If so, it runs the query against the
local cache only and jumps to step 14 below.
4) The EntityManager raises a Fetching event. Listeners can see the query
and, optionally, cancel the query.
5) The EntityManager sends the query along with authentication information
to the EntityServer on the middle tier. It may modify the request before
sending it to the EntityServer if it can determine that some of desired entities
are already in the client side cache.
Middle Tier
EntityServer
6) The EntityServer authenticates the client (the currently logged in "user")
and creates a new instance of either a custom or a default
EntityServerQueryInterceptor. The EntityServerQueryInterceptor is
executed and it can either modify the query and/or run any developer-
specified security checks in the AuthorizeQuery handler. If security checks
fail, it raises a security exception and sends this back to the client tier.
7) Having passed security checks, the EntityServerQueryInterceptor calls its
base ExecuteQuery method where the EntityServer converts the, possibly
modified, query into a format applicable to the datasource being
queried. This will often be an Entity Framework LINQ to Entities query.
Data source
Data Source
8) The data source performs the query or queries and returns one or more result
sets back to the EntityServer.
Middle Tier
EntityServer
9) The Entity Framework converts the result sets returned from the data
source into ADO.NET entities and delivers them to the
EntityServerQueryInterceptor ( from above) and performs any post query
authorization via the AuthorizeQueryResult method.
10) The EntityServer repackages the result set into a format that can be
transmitted efficiently. It then ships the entity data back to the client side
EntityManager.
11) After transmission, the EntityServer allows the servers local copy of the
entities to go out of scope and the garbage collector reclaims them. This
enables the EntityServer to stay stateless.
Client Tier
EntityManager
12) Compares fetched entities to entities already in the cache. Adds new
entities to the cache. Replaces matching cached entities that are unmodified
(in essence refreshing them). Preserves cached entities with pending
modifications because the query strategy is normal.
13) Reapplies the original query to the cache to locate all desired entities.
14) Raises the Queried event. Listeners can examine the list of entities
actually retrieved from the data source.
15) Returns the desired entities to the application.
Client Tier
Application
Code
16) The entities are available for processing.
Client-side life cycle
Last modified on March 23, 2011 22:56
Client-side query life cycle events on the EntityManager include Querying, Fetching, and
Queried. These are summarized in the table below.
DevForce raises the client-side Querying event as query execution begins. The Fetching event
is raised before sending the query to the EntityServer; if a query can be satisfied from cache,
then Fetching is not raised. The Queried event is raised just before returning query results.
We can listen to these events by attaching a custom handler.
Both the Querying and the Fetching events provide the query object. Your handler can
examine the object (it implements IEntityQuery and choose to let the query continue as is,
continue after modification, or cancel it. If you cancel the query, the Entity Manager method
returns as if it found nothing. If the method returns a scalar entity, it yields the return entity
types Null Entity; otherwise, it returns a null entity list. Beware of canceling an entity
navigation list query method.
The Queried event fires just before the query method returns. Entities have been fetched and
merged into the cache. The event arguments include a list, EntitiesChanged, of any entities
added to or modified in the cache. Note that this list could include entities of the target entity
type the kind we expected returned from the query but also of other types brought in via
Includes or by virtue of query inversion.
Client-Side Life-Cycle Events
Event EventArgs Comments
Typical Uses of the
Corresponding Event
Handler
Querying EntityQueryingEventArgs
Raised as query execution begins.
Provides access to the submitted
query.
Modify the query being
submitted, or refuse the
request for data.
Fetching EntityFetchingEventArgs
Raised before sending the query
to the EntityServer.
Provides access to the submitted
query. If a query can be satisfied
from cache, Fetching is not
raised.
Modify the query being
submitted, or refuse the
request for data.
Queried EntityQueriedEventArgs
Raised just before returning
query results.
Provides access to the complete
result set, as well as the subset
representing changes to the
cache.
Modify the objects that
were returned by the
query
Corresponding to each of these events is a protected virtual method on the EntityManager that
can be used to perform the same task directly in a subclassed EntityManager.
Member Summary
OnQuerying
The virtual method that a derived EntityManager can override to raise the Querying
event.
OnFetching
The virtual method that a derived EntityManager can override to raise the Fetching
event.
OnQueried
The virtual method that a derived EntityManager can override to raise the Queried
event.
EntityQueryingEventArgs
Property PropertyType Access Description
Query IEntityQuery get, set
The query about to be executed. The query can be modified here,
but the final shape must remain the same.
Cancel bool get, set Allows the query to be canceled.
EntityFetchingEventArgs
Property PropertyType Access Description
Query IEntityQuery get
The query about to be executed. The query can no longer be
modified here, use the Querying event if you need modification.
Cancel bool get, set Allows the query to be canceled.
EntityQueriedEventArgs
Note that this is the non-generic version of the EntityQueriedEventArgs<T> class. As a result
the Query and Results properties here are non-generic as well. i.e. IEntityQuery vs
IEntityQuery<T>, IEnumerable vs IEnumerable<T>.
Property PropertyType Access Description
Query IEntityQuery get The query just executed.
Results IEnumerable get The results of the query.
ChangedEntities IList<Object> get
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 get
Whether the operation actually required a trip to the
database. Many queries can be completed without
having to go to the database.
ResolvedFetchStrategy FetchStrategy get
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.
Server-side life cycle
Queries processed by the EntityServer pass through an instance of the DevForce
EntityServerQueryInterceptor. You can alter the course of that processing by creating a
'custom' subclass of the EntityServerQueryI nterceptor and overriding its virtual properties
and template methods. DevForce can discover the existence of your class automatically.


Interceptor design guidelines
You don't have to write a custom interceptor class. The EntityServer will use the DevForce
EntityServerQueryInterceptor if it doesn't find a custom subclass. Many production
applications do include a custom interceptor.
The EntityServerQueryInterceptor class resides in the IdeaBlade.EntityModel.Server
assembly which must be referenced by the project that contains your custom subclass.
You can write only one custom interceptor. It should be a public class and must have a public
default, parameterless constructor (if it has a constructor).
Please keep your named custom interceptor stateless if possible. DevForce creates a new
instance of this class for each query performed by the server so you generally don't have to
worry about threading issues with instance state. If you decide to maintain static state, give
great care to ensuring safe concurrent access to that state.
Avoid putting anything in the interceptor other than what is strictly necessary to achieve its
purpose. The interceptor is a poor choice for a grab-bag of server-side features.
You don't have to override any of the template methods; the default base implementations all
work fine. You may wish to be explicit in your custom class and override every template
method; your override can simply delegate to the base implementation.
Make sure that the assembly containing your custom interceptor is deployed to the server such
that it can be discovered. Assembly discovery is discussed here.
Interceptor template methods
Most of the template methods provided by the EntityServerQueryInterceptor base class have
no parameters because all of the relevant data are provided by properties and methods on each
instance of the class. This also allows IdeaBlade to extend these base classes in the future
without breaking custom developer code.
Many of the template methods described below return a boolean result with a base
implementation that returns true. A return value of false indicates that the operation should
be cancelled. Query results include a flag to indicate a cancelled operation. Note that the
base implementation of the authorization method does not return false. It treats an
unauthorized query as an exception, not a cancellation.
Method Typical Uses
AuthorizeQuery Determine if the user is authorized to make the request.
FilterQuery Modify the query as needed.
ExecuteQuery
Can intercept immediately before and after the query is executed. Always call
the base method to allow DevForce to execute the query.
AuthorizeQueryResult Allows for authorization of types in the result set.
In addition to the above, there are supporting properties or methods that can be overridden.
For data retrieval, these include
DefaultAuthorization
ClientCanQuery, and
ShouldAuthorizeQueryResult
Authorization
During data retrieval operations, the first interceptor called is AuthorizeQueryResult(). The
default implementation checks the ClientCanQuery property, passing it the target type of the
query. ClientCanQuery in turn checks the DefaultAuthorization property.
If you select an Entity in the Entity Data Model Designer, you will see associated DevForce
Code Generation properties named Can Query and Can Save. By default, these have their
values set to the value Default; other options are True and False.

If you leave the default values unchanged and you also leave unchanged the value of
DefaultAuthorization property of your EntityServerQueryInterceptor class, then all entity
types will be allowed in queries and saves. You can however override the settings in the
EDMX file with code in your EntityServerQueryInterceptor.
C#
/// <summary>
///
/// </summary>
/// <remarks>
/// Override this property to change the Default authorization result (whether
/// authorization succeeds if no Authorization attributes are found).
///
/// The default is true - allowing any entity type not specifically marked
/// with an authorization attribute to be queried.
/// </remarks>
protected override bool DefaultAuthorization {
// Always require explicit authorization attributes on entities.
get { return false; }
}
VB
''' <summary>
'''
''' </summary>
''' <remarks>
''' Override this property to change the Default authorization result (whether
''' authorization succeeds if no Authorization attributes are found).
'''
''' The default is true - allowing any entity type not specifically marked
''' with an authorization attribute to be queried.
''' </remarks>
Protected Overrides ReadOnly Property DefaultAuthorization() As Boolean
' Always require explicit authorization attributes on entities.
Get
Return False
End Get
End Property
You have just ordered that entities types are not authorized for queries, by default. An attempt
to execute a query such as the following
C# var customersQuery = _em1.Customers.ToList();
VB Dim customersQuery = _em1.Customers.ToList()
now results in an exception, thrown in response to the call to base.AuthorizeQuery():

If, however, you return to the EDM Designer and set the Can Query property on the Customer
entity to True, then you will again be able to submit queries against the Customer type.
Suppose, having set DefaultAuthorization to false, you were to authorize the Order type
(along with the Customer type), and then submit the following query:
C#
var ordersQuery = _em1.Orders
.Include("Customer")
.Include("OrderDetails").ToList();
VB
Dim ordersQuery = _em1.Orders _
.Include("Customer") _
.Include("OrderDetails").ToList()
The query is requesting Orders and Customers, both of which you have explicitly designated
as queryable; but also OrderDetails, which you have not made queryable. Is the query
executed?
If fact it is, as the ClientCanQuery test only looks at the target QueryableType of the query.
To enforce a proscription on the retrieval of OrderDetails by way of Includes, you will need to
implement logic to screen OrderDetails in an override of the AuthorizeQueryResult()
interceptor, and also override the ShouldAuthorizeQueryResult property, setting its value to
true:
C#
protected override bool AuthorizeQueryResult() {
int countOrderDetails = this.QueriedEntities
.Where(e => e.GetType() == typeof(OrderDetail)).Count();
if (countOrderDetails > 0) {
return false;
}
return true;
}

protected override bool ShouldAuthorizeQueryResult {
get {
return true;
}
}
VB
Protected Overrides Function AuthorizeQueryResult() As Boolean
Dim countOrderDetails As Integer = Me.QueriedEntities.Where _
(Function(e) e.GetType() Is GetType(OrderDetail)).Count()
If countOrderDetails > 0 Then
Return False
End If
Return True
End Function

Protected Overrides ReadOnly Property ShouldAuthorizeQueryResult() As Boolean
Get
Return True
End Get
End Property
Such logic would result in an exception upon the attempt to submit the query:
Filtering the query
If the query is authorized, execution proceeds and the FilterQuery interceptor is called. Here
you may add filters conditions to the query such as these:
C#
/// <summary>
///
/// </summary>
/// <returns></returns>
/// <remarks>
/// May be overridden to perform any logic before the query is submitted.
/// This can include adding to the QueryFilters collection or by modifying
/// the query directly using the Query.Filter method or the
/// QueryFilterCollection classes.
/// </remarks>
protected override bool FilterQuery() {
// Restrict Customer and Employee results to those based in the UK
QueryFilters.AddFilter<Customer>(q => q.Where(c => c.Country == "UK"));
QueryFilters.AddFilter<Employee>(q => q.Where(e => e.Country == "UK"));
return true;
}
VB
''' <summary>
'''
''' </summary>
''' <returns></returns>
''' <remarks>
''' May be overridden to perform any logic before the query is submitted.
''' This can include adding to the QueryFilters collection or by modifying
''' the query directly using the Query.Filter method or the
''' QueryFilterCollection classes.
''' </remarks>
Protected Overrides Function FilterQuery() As Boolean
' Restrict Customer and Employee results to those based in the UK
QueryFilters.AddFilter(Of Customer)(Function(q) q.Where _
(Function(c) c.Country = "UK"))
QueryFilters.AddFilter(Of Employee)(Function(q) q.Where _
(Function(e) e.Country = "UK"))
Return True
End Function
Executing the query
Next, the ExecuteQuery() interceptor is called. That should include a call to
base.ExecuteQuery(), which will actually execute the submitted query. You can insert logic
both before and after the call to base.ExecuteQuery().
Virtual methods in more detail
Virtual methods listed in the order that they will be called -
protected virtual bool AuthorizeQuery()
Determines whether the query can be executed. The base implementation call performs an
analysis of the query expression tree by calling the ClientCanQuery method defined below for
each entity type used in the query to determine if any unauthorized types are being accessed.
Note that this will not detect the case where a polymorphic query is executed against a base
type and one of its subtypes has a ClientCanQuery restriction. In this case, the
ShouldAuthorizeQueryResult property should be set to true and the AuthorizeQueryResult
method may be implemented. It is not usually necessary to override the AuthorizeQueryResult
method; simply returning true from ShouldAuthorizeQueryResult is usually sufficient.
protected virtual bool FilterQuery()
Provides a point at which the Query property can be modified before the query is executed.
Optionally, the QueryFilters property can be utilized to add filters that will be applied when
the query is actually executed, without actually modifying the Query property itself.
protected virtual bool ExecuteQuery()
Performs the actual execution of the query. The query itself may be modified before calling
the base implementation of this method and logging or other post processing operations may
be performed after the base implementation is called. Note that the base implementation must
be called in order for the query to be executed. It is during the call to the base implementation
that any QueryFilters defined earlier will be applied.
protected virtual bool AuthorizeQueryResult()
This method is only called if the ShouldAuthorizedQueryResult property returns true. This
methods base implementation actually walks through all of the entity types to be returned
and throws an exception if the ClientCanQuery method below returns false for any of the
specified types. The QueriedEntities collection mentioned below is also available and may be
used to examine every entity being returned.
Other virtual properties and methods -
protected virtual bool DefaultAuthorization { get; }
This property defines the default authorization behavior for any types that do not have a
ClientCanQuery attribute defined. The base implementation returns true which means that
by default any type not otherwise restricted is queryable. By returning a false here, any types
that are not specifically marked as queryable will restricted.
protected virtual bool ClientCanQuery(Type type)
This method is called from the base implementation of both the AuthorizeQuery as well as the
AuthorizeQueryResult methods. It may be overridden to add additional restrictions or to relax
existing ones. If adding restrictions, make sure that the base implementation is called.
Helper properties
protected IEntityQuery Query { get; set; }
The current query. This can be modified anytime before query execution.
protected EntityQueryFilterCollection QueryFilters { get; }
A collection of Query filters that will automatically applied to every query. Use the
FilterQuery method to add or remove filters from this collection.
protected bool IsServerQuery { get; }
Returns true if the 'current query' was issued on the server. This can occur as a result of a
query made from within this interceptor using the EntityManager mentioned below or as a
result of a query invoked by a server implementation of an InvokeServerMethod call.
protected EntityManager EntityManager { get; }
An untyped EntityManager that can be used to query for additional information. Note that
this is not the original client-side EntityManager on which the query request was made. It is a
'preauthenticated' server-side EntityManager, and its cache is empty. Because of its
"preauthenticated" nature, there is no Principal attached to this entity manager and any
operations that it performs bypass regular authentication. Because this EntityManager can
only be accessed on the server from within code deployed to the server all operations that it
performs are considered "priviledged".
Because this EntityManager is untyped, any entity type may queried with it. Queries against
this EntityManager are usually composed via a technique shown in the following example, (
the code below is assumed to be executing within the context of some
EntityManagerQueryInterceptor method). Note the use of the EntityQuery<T> constructor.
C#
var newQuery = new EntityQuery<Customer>().Where(c => c.CompanyName.StartsWith("S"))
var custs = newQuery.With(EntityManager).ToList();
protected IList<Object> QueriedEntities { get; }
This property is only available after the query has executed and returns a list of every entity
that was queried, whether directly or thru an 'Include' or 'Query Inversion'. Any modifications
to this collection will be ignored.
protected IPrincipal Principal { get; }
The IPrincipal from the user session requesting this operation.
BETA Features
The following features may or may not be retained in the product in the future, and please contact
support with any feedback that you have regarding them.
protected void ForceResult(Object result, NavigationSet navSet = null, QueryInfo
queryInfo = null)
May be called to force the results of the query. The shape of the result being foreced must
match that of the
result of the query being executed. This method can be called either before or after the
execution of the query.

protected bool ResultsForced { get; }
Returns true if the ForceResult call above was made.
Intercepting and modifying queries during execution
There will be points where the need arises to intercept and modify a query while it is
executing. DevForce provides an extension method, Filter(), that can be used to superimpose
one or more independently defined filter conditions upon an existing query.
Filter extension method
Filter() differs from Where() in two ways
1) Filters can be safely applied to queries that do not 'fit' the type of the query being
processed. In these cases the Filter is simply ignored.
2) Filters operate on any subselects within the query in addition to result type of the query.
Where clause's operate in a chained fashion on whatever result type immediately precedes
them.
Filter()s primary motivating use case is the need to apply query interception, either client or
server-side, to submitted queries; although it is perfectly possible to use it in other contexts. In
the case of query interception, there is a need to work with 'untyped' queries, or queries where
both the return type as well as the source type of a query is very likely unknown at runtime, so
there is a need to be able to apply a possibly large number of 'Filter's to any query that comes
though and only have the 'applicable' filters apply to each query. Additionally, there is often a
need to modify 'intermediate' portions of the query in addition to just restricting its final
result.
For example, suppose your applications database includes data for customers worldwide, but
that a given Sales Manager only works with data for customers from his region. Instead of
baking the region condition into every query for Customers throughout your application, you
could implement an EntityServerQueryInterceptor that imposes the condition upon any query
for customers made while that Sales Manager is logged in.
The usefulness of Filter() becomes even more apparent when you need to apply filters in a
global way for more than one type.
There are several overloads of Filter(), one that takes a Func<T> and another that takes an
EntityQueryFilterCollection (each of whose members is a Func<T>). Lets look at some
examples:
C#
var query = _em1.Territories.Where(t => t.TerritoryID > 100);
var newQuery = query.Filter((IQueryable<Territory> q) =>
q.Where(t => t.TerritoryDescription.StartsWith("M")));
VB
Dim query = _em1.Territories.Where(Function(t) t.TerritoryID > 100)
Dim newQuery = query.Filter(Function(q As IQueryable(Of Territory)) _
q.Where(Function(t) t.TerritoryDescription.StartsWith("M")))
In this example we have used the overload of Filter which takes as its argument a Func
delegate. Said delegate takes an IQueryable<T> -- essentially a list of items of type T and
returns an IQueryable<T>. The IQueryable<T> that goes in is the one defined by the variable
query, defined as
C# _em1.Territories.Where(t => t.TerritoryID > 100)
VB _em1.Territories.Where(Function(t) t.TerritoryID > 100)
The one that comes out is the one that went in minus those Territories whose Description
property value begins with the letter M.
In the first example, above, our filter applies to the querys root type, Territory. We arent
limited to that: we can also apply filters to other types used in the query. Consider the
following:
C#
var q1 = _em1.Customers.SelectMany(c => c.Orders
.Where(o => o.ShipCity.StartsWith("N")));
var q1a = q1.Filter((IQueryable<Order> q) =>
q.Where(o => o.FreightCost > maxFreight));
VB
Dim q1 = _em1.Customers.SelectMany(Function(c) c.Orders. _
Where(Function(o) o.ShipCity.StartsWith("N")))
Dim q1a = q1.Filter(Function(q As IQueryable(Of Order)) q. _
Where(Function(o) o.FreightCost > MaxFreight))
The root type for this query is Customer, but the query projects OrderSummaries as its output,
and it is against OrderSummaries that we apply our filter. This time the filter imposes a
condition upon the values of the OrderSummary.Freight property. Without the filter we
would have retrieved all OrderSummaries having a ShipCity whose name begins with "N";
with the filter, not only must the name begin with "N", but the Freight property value must
exceed the value maxFreight.
Lets look at another example of filtering one some type other than the querys root type:
C# var q1 = _em1.Customers.Where(c => c.Orders.Any
(o => o.ShipCity.StartsWith("N")));
var q1a = q1.Filter((IQueryable<Order> q) =>
q.Where(o => o.FreightCost > maxFreight));
{{/code}}
VB
Dim q1 = _em1.Customers.Where(Function(c) c.Orders.Any _
(Function(o) o.ShipCity.StartsWith("N")))
Dim q1a = q1.Filter(Function(q As IQueryable(Of Order)) q. _
Where(Function(o) o.FreightCost > MaxFreight))
In the absence of the filter, the above query would retrieve Customer objects: specifically,
Customers having at least one Order whose ShipCity begins with the letter "N". The filter
potentially reduces the set of Customers retrieved by imposing an additional condition on
their related OrderSummaries (again, on the value of their Freight property).
Now lets look at a use of Filter() involving conditions on more than a single type.
C#
var eqFilters = new EntityQueryFilterCollection();
eqFilters.AddFilter((IQueryable<Customer> q) =>
q.Where(c => c.Country.StartsWith("U")));
eqFilters.AddFilter((IQueryable<Order> q) =>
q.Where(o => o.OrderDate < new DateTime(2009, 1, 1)));
var q0 = _em1.Customers.Where(c => c.Orders.Any
(o => o.ShipCity.StartsWith("N")));
var q1 = q0.Filter(eqFilters);
VB
Dim eqFilters = New EntityQueryFilterCollection()
eqFilters.AddFilter(Function(q As IQueryable(Of Customer)) q. _
Where(Function(c) c.Country.StartsWith("U")))
eqFilters.AddFilter(Function(q As IQueryable(Of Order)) q. _
Where(Function(o) o.OrderDate < New Date(2009, 1, 1)))
Dim q0 = _em1.Customers.Where(Function(c) c.Orders.Any( _
Function(o) o.ShipCity.StartsWith("N")))
Dim q1 = q0.Filter(eqFilters)
In the above snippet, we instantiate a new EntityQueryFilterCollection, to which we then add
two individual filters, each of which is a Func<T>. The first filter added imposes a condition
on the Customer type; the second imposes a condition on the OrderSummary type. Note that
we could now apply these filters to any query whatsoever. If the targeted query made use of
the Customer type, the condition on Customers would apply; if it made use of the
OrderSummary type, the condition on OrderSummaries would apply. If it made use of both,
as does our example q0, both conditions would apply.
A filter is also applied directly to any clause of a query that returns its targeted type. Thus, the
effect of the two filters defined above, applied against query q0, is to produce a query that
would look like the following if written conventionally:
C#
var q0 = _em1.Customers
.Where(c => c.Country.StartsWith("U"))
.Where(c => c.Orders
.Where(o => o.OrderDate < new DateTime(2009, 1, 1))
.Any(o => o.ShipCity.StartsWith("N")));
VB
Dim q0 = _em1.Customers. _
Where(Function(c) c.Country.StartsWith("U")). _
Where(Function(c) c.Orders. _
Where(Function(o) o.OrderDate < New Date(2009, 1, 1)). _
Any(Function(o) o.ShipCity.StartsWith("N")))


Build queries dynamically
Last modified on October 27, 2011 13:09
Contents
The problem
The ESQL option
LINQ expressions are strongly typed and static. They are easy to compose when you know
the type of thing you want to query at compile time. But they are difficult to create if you
don't know the type until the application runs. Many applications let the user specify the entity
type to retrieve, the criteria to filter with, the properties to sort and group by. DevForce
dynamic query building components help you build and execute LINQ queries on the fly
based on information supplied at runtime.


The problem
"LINQ" stands for "Language Integrated Query". LINQ is designed to be written in the
same manner as other code, rubbing shoulders with procedural statements in the body of your
application source files. C# and Visual Basic are statically typed languages so the main
pathway for writing LINQ queries is to compose them statically as strongly typed query
objects that implement the IQueryable<T> interface. Standard LINQ queries, and almost of
the LINQ examples in the DevForce Resource Center, are static and strongly typed. Here is a
typical example:
C#
IQueryable<Customer> customers = _myEntityManager.Customers;
var query = customers.Where(c => c.CompanyName = "Acme");
VB
Dim customers As IQueryable(Of Customer) = _myEntityManager.Customers
Dim query = customers.Where(Function(c) c.CompanyName = "Acme")
The _myEntityManager.Customers expression returns an instance of a query object that
implements IQueryable<Customer>. The strongly typed nature of the expression is what
allows IntelliSense and the compiler to interpret the remainder of the statement.
What if 'T' (Customer in this case) is not known until runtime; from a compiler perspective we
no longer have an IQueryable<T> but have instead just an IQueryable. And IQueryable,
unfortunately, does not offer any of the extension methods that we think of a standard LINQ;
in other words, no Where, Select, GroupBy, OrderBy, Any, Count etc, methods.
How do we write a query when we don't have the type available at runtime?
C#
var typeToQuery = typeof(Customer);
IQueryable<???> someCollection = << HOW DO I CREATE AN IQUERYABLE OF "typeToQuery"?>> ;
var query = somecollection.Where( << HOW DO I COMPOSE A LAMBDA EXPRESSION WITHOUT A
COMPILE TIME TYPE >> );
VB
Dim typeToQuery = GetType(Customer)
IQueryable(Of ???) someCollection = << HOW DO I CREATE AN IQUERYABLE OF
"typeToQuery"?>>
Dim query = somecollection.Where(<< HOW DO I COMPOSE A LAMBDA EXPRESSION WITHOUT A
COMPILE TIME TYPE >>)
A second issue can occur even if we know the type of the query but we have a number of
'where conditions' or predicates, that need to be combined. For example
C#
Expression<Func<Customer, bool>> expr1 = (Customer c) => c.CompanyName.StartsWith("A");
Expression<Func<Customer, bool>> expr2 = (Customer c) => c.CompanyName.StartsWith("B");
VB
Dim expr1 As Expression(Of Func(Of Customer, Boolean)) = _
Function(c As Customer) c.CompanyName.StartsWith("A")
Dim expr2 As Expression(Of Func(Of Customer, Boolean)) = _
Function(c As Customer) c.CompanyName.StartsWith("B")
It turns out that we can use either of these expressions independently, but it isn't obvious how
to combine them.
C#
var query1 = myEntityManager.Customers.Where(expr1); // ok
var query2 = myEntityManager.Customers.Where(expr1); // ok
var queryBoth = myEntityManager.Customers.Where(expr1 && expr2) // BAD - won't compile.
VB
Dim query1 = myEntityManager.Customers.Where(expr1) ' ok
Dim query2 = myEntityManager.Customers.Where(expr1) ' ok
Dim queryBoth = myEntityManager.Customers.Where(expr1 AndAlso expr2) ' BAD - won't
compile.
The ESQL option
You can construct queries on the fly using DevForce "pass-thru" Entity SQL (ESQL). ESQL
queries are strings that look like standard SQL, differing primarily (and most obviously) in
their references to entity types and properties rather than tables and columns. You can build
ESQL queries by concatenating strings that incorporate the runtime query critieria you
gleaned from user input.
Most developers prefer to construct LINQ queries with DevForce for two reasons:
1. Building syntactically correct ESQL strings can be more difficult to do correctly than writing
DevForce dynamic queries. The dynamic query approach affords a greater degree of compiler
syntax checking and the structure of the query is more apparent. You often know most of the
query at design time; when only some of the query is variable you can mix the statically
typed LINQ statements with the dynamic clauses ... as described in the topic detail.
2. ESQL queries must be sent to and processed on the server. You cannot apply ESQL queries to
the local entity cache. LINQ queries, on the other hand, can be applied to the database, to
the cache, or to both. This is as true of dynamic LINQ queries as it is of static queries. For
many developers this is reason enough to prefer LINQ to ESQL.

Create a completely dynamic query
Last modified on October 27, 2011 15:30
Contents
EntityQuery.Create
LINQ methods where no IQueryable<T> exists
Most of the queries created using DevForce will be instances of some query subclass that
implements IQueryable<T>. However, there will be cases where we will not be able to
determine "T" until runtime. A "completely dynamic" query is one where we do not know the
type "T" of the query at compile time. Because these queries cannot implement
IQueryable<T> they will instead implement the IQueryable interface.


EntityQuery.Create
The static EntityQuery.Create is a non-generic method that creates a new query for a specified
type. Here is a function that employs EntityQuery.Create to produce a query that retrieves
every instance of a type:
C#
public EntityQuery GetAll(Type entityType, EntityManager manager)
{
return EntityQuery.Create(entityType, manager);
}
VB
Public Function GetAll(ByVal entityType As Type, ByVal manager as EntityManager) As
EntityQuery
Return EntityQuery.Create(entityType, manager)
End Function
It's a contrived example but you can imagine something like it supporting an application
feature that lets users pick the type of entity to retrieve from a list. We use it to retrieve
Products and compare this approach with the strongly typed LINQ statement that does the
same thing ... when you know that you are always getting Products:
C#
var queryType = typeof(Product); // the type picked by the user
EntityQuery query1 = GetAll(queryType, anEntityManager);
EntityQuery<Product> query2 = anEntityManager.Products;
VB
Dim queryType = GetType(Product) ' the type picked by the user
Dim query1 As EntityQuery = GetAll(queryType, anEntityManager)
Dim query2 As EntityQuery(Of Product) = anEntityManager.Products
These two queries are identical from the standpoint of how they get executed and what they
return. The critical difference is that the compiler can't know the type of the query returned in
the first case and therefore must return an EntityQuery (which implements IQueryable and
ITypedQuery) instead of EntityQuery<T> (which implements IQueryable<T>).
This has three ramifications:
Completely dynamic queries typically derive from EntityQuery which implements IQueryable
and ITypedQuery.
These queries must be executed either with the IEntityQuery.Execute extension method or
the EntityManager.Execute method; you can't use ToList().
Such queries return IEnumerable results instead of IEnumerable<T>.
The following example illustrates these points:
C#
// IQueryable implementation
var query1 = EntityQuery.Create(typeof(Product), anEntityManager);
// can't call query1.ToList() because query1 is not an IQueryable<T>
IEnumerable results = query1.Execute();
// Have to cast to work with Products
IEnumerable<Product> products1 = results.Cast<Product>();

// IQueryable<T> implementation
var query2 = anEntityManager.Products;
IEnumerable<Product> products2 = query2.ToList();
VB
' IQueryable implementation
Dim query1 = EntityQuery.Create(GetType(Product), anEntityManager)
' can't call query1.ToList() because query1 is not an IQueryable<T>
Dim results As IEnumerable = query1.Execute()
' Have to cast to work with Products
Dim products1 As IEnumerable(Of Product) = results.Cast(Of Product)()

' IQueryable<T> implementation
Dim query2 = anEntityManager.Products
Dim products2 As IEnumerable(Of Product) = query2.ToList()
LINQ methods where no IQueryable<T> exists

LINQ queries, as defined in standard .NET depend on the IQueryable<T> and
IEnumerable<T> interfaces. Because a "completely dynamic" query only implements the
IQueryable interface there is no way to implement the "standard" LINQ operators. However,
DevForce does provide a substitute.
DevForce implements a separate set of extension methods that have the same names as the
standard LINQ operators but operate on instances of objects that only implement IQueryable
instead of IQueryable<T>. ( See IdeaBlade.Linq.QueryableExtensions). That covers many of
the familiar LINQ operators and immediate execution methods.
Some extension methods require further refinment to operate specifically on instances of
DevForce EntityQuery (as opposed to EntityQuery<T>. These methods may be found in
IdeaBlade.EntityModel.EntityQueryExtensions along side the other EntityQuery extension
methods. They are distinguishable by their first parameter which is of type
ITypedEntityQuery.
The ITypedEntityQuery interface describes an EntityQuery that is actually an EntityQuery<T> but the
type "T" will not be known until runtime and is therefore not available at compile time. This is not
something that a developer will usually ever have to concern himself/herself with.
The EntityQueryExtensions include the following methods that return an ITypedEntityQuery.
EntityQueryExtensions.Where
EntityQueryExtensions.OrderBySelector
EntityQueryExtensions.Select
EntityQueryExtensions.SelectMany
EntityQueryExtensions.GroupBy
EntityQueryExtensions.Take
EntityQueryExtensions.Skip
EntityQueryExtensions.Cast
EntityQueryExtensions.OfType
as well as the following immediate execution methods that take an ITypedEntityQuery and
return a scalar result.
EntityQueryExtensions.All
EntityQueryExtensions.Any
EntityQueryExtensions.Contains
EntityQueryExtensions.Count
An overload of EntityQueryExtensions.AsScalarAsync also extends ITypedEntityQuery so you
can call the asynchronous scalar functions {First..., Count, etc.).
These overloads differ from the standard LINQ overloads in that none of them involve
parameters that are Expression<Func<T, ...>. This is again a ramification of the fact that the
generic type "T" is not available at compile time for these methods. These methods instead
take either a PredicateDescription, SortSelector, or ProjectionSelector in place of the strongly
typed Expression<...>

Create dynamic "Where" clauses
Last modified on October 27, 2011 15:30
Contents
Flavors of dynamic where clauses
Whats a predicate?
Create a Where clause with two predicates
Completely dynamic query
The need for the ability to create a dynamic where clause occurs fairly frequently in
applications that need to filter data based on a users input. In these cases you don't really
know ahead of time what properties a user is going to want to query or what the conditions
of the query are likely to be. In fact, you may not even know the type that you will be
querying for until runtime. So you will need to be able to compose the query based on the
inputs determined at runtime.


Flavors of dynamic where clauses

Ideally, when building a query we want to specify as little dynamically as we have to. The
less dynamic a query is the better the compile time checking and intellisense will be for the
query. Everything depends upon what we know and when we know it. Do we know the type
of the query at compile time but need to wait until runtime to determine the properties to be
queried and the conditions regarding these properties? Or do we not even know the type of the
query until runtime?
Whatever the case, the IdeaBlade.Linq.PredicateBuilder and the
IdeaBlade.Linq.PredicateDescription classes are the tools used to deal with compile time
uncertainty. As we review the PredicateBuilder API, you will see both typed and untyped
overloads for most methods in order to support both compile and runtime scenarios.
Whats a predicate?
A LINQ where clause is intimately tied to the concept of a "predicate". So what is a predicate
and how does it relate to a LINQ where clause.
A predicate is a function that evaluates an expression and returns true or false. The code
fragment...
C# p.ProductName.Contains("Sir")
VB p.ProductName.Contains("Sir")
...is a predicate that examines a product and returns true if the products ProductName
contains the Sir string.
The CLR type of the predicate in our example is:
C# Func<Product, bool>
VB Func(Of Product, Boolean)
Which we can generalize to:
C# Func<T, bool>
VB Func(Of T, Boolean)
This is almost what we need in order to build a LINQ where clause. The LINQ Where
extension method is defined as follows:
C#
public static IQueryable<T> Where<TSource>(
this IQueryable<T> source1, Expression<Func<T,bool>> predicate)
VB
public static IQueryable(Of T) Where(Of TSource) _
(Me IQueryable(Of T) source1, Expression(Of Func(Of T,Boolean)) predicate)
Note that the "predicate" parameter above is
C# Expression<Func<T, bool>>
VB Expression(Of Func(Of T, Boolean))
When we refer to the idea that a "predicate" is needed in order to build a LINQ where clause,
what we really mean is that we need to build a "predicate expression", or a Expression that is
resolvable to a simple predicate.
Create a Where clause with two predicates
The snippet below comprises two statements, each of which uses PredicateBuilder.Make to
create a PredicateDescription representing a single predicate (filter criteria).
C#
PredicateDescription p1 = PredicateBuilder.Make(typeof(Product), "UnitPrice",
FilterOperator.IsGreaterThanOrEqualTo, 24);
PredicateDescription p2 = PredicateBuilder.Make(typeof(Product), "Discontinued",
FilterOperator.IsEqualTo, true);
VB
Dim p1 As PredicateDescription = PredicateBuilder.Make(GetType(Product), "UnitPrice", _
FilterOperator.IsGreaterThanOrEqualTo, 24)
Dim p2 As PredicateDescription = PredicateBuilder.Make(GetType(Product), "Discontinued", _
FilterOperator.IsEqualTo, True)
A new query can then be composed and executed by an EntityManager as usual:
C#
var query = anEntityManager.Products.Where(p1.And(p2))
// The above query is the same as:
//var queryb = anEntityManager.Products.Where(p => p.UnitPrice > 24 && p.Discontinued);
VB
Dim query = anEntityManager.Products.Where(p1.And(p2))
' The above query is the same as:
'var queryb = anEntityManager.Products.Where(p => p.UnitPrice > 24 && p.Discontinued);
We could have combined the individual PredicateDescriptions into another
PredicateDescription variable:
C#
CompositePredicateDescription p3 = p1.And(p2);
var query = anEntityManager.Products.Where(p3);
VB
Dim p3 As CompositePredicateDescription = p1.And(p2)
Dim query = anEntityManager.Products.Where(p5)
Learn more about combining predicates with PredicateBuilder and PredicateDescription
classes.
Completely dynamic query
The Where clause in the previous examples were still applied to a strongly typed (non-
dynamic) IQueryable<Product> implementation. To be more precise, the query root was of
type IEntityQuery<Product>.
What if we didn't know we were querying for Product at compile type? We'd know the type at
runtime but we didn't know it as we wrote the code. We could use the
EntityQuery.CreateQuery factory method and pass it the runtime type. CreateQuery returns a
nominally-untyped EntityQuery object.
C#
var queryType = typeof(Product); // imagine this was passed in at runtime.
var baseQuery = EntityQuery.CreateQuery(queryType , anEntityManager);
var query = baseQuery.Where(p1.And(p2));
VB
Dim queryType = GetType(Product) ' imagine this was passed in at runtime.
Dim baseQuery = EntityQuery.CreateQuery(queryType , anEntityManager)
Dim query = baseQuery.Where(p1.And(p2))
The EntityQuery result of CreateQuery implements ITypedEntityQuery. The Where clause in
this example made use of the ITypedEntityQuery extension method instead of the
IQueryable<T> extension method:
C#
public static ITypedEntityQuery Where(this ITypedEntityQuery source, IPredicateDescription
predicateDescription);
VB
Public Shared ITypedEntityQuery Where(Me ITypedEntityQuery source, _
IPredicateDescription predicateDescription)
The query that will be executed is exactly the same regardless of which extension method is
used. Both queries are Product queries. The critical difference is that the compiler can't
determine the type of the query in the second case. That's why it resolved to a query typed as
ITypedEntityQuery, which implements IQueryable, instead of IEntityQuery<T> which
implements IQueryable<T>.
There are two ramifications:
Completely dynamic queries, those typed as ITypedEntityQuery, must be executed with one
of the EntityManager.Execute methods instead of ToList().
The compiler declares that the type of the dynamic query execution result is IEnumerable
instead of IEnumerable<T>.
The following example illustrates:
C#
// IQueryable<T> implementation
var query1 = anEntityManager.Products.Where(p3);
IEnumerable<Product> products1 = query1.ToList();
// IQueryable implementation
var baseQuery = EntityQuery.CreateQuery(typeof(Product), anEntityManager);
var query2 = baseQuery.Where(p1.And(p2));
// can't call query2.ToList() because query2 is not an IQueryable<T>
IEnumerable results = anEntityManager.ExecuteQuery(query2);
// next line is required in order to
IEnumerable<Product> products2 = results.Cast<Product>();
VB
' IQueryable<T> implementation
Dim query1 = anEntityManager.Products.Where(p3)
Dim products1 As IEnumerable(Of Product) = query1.ToList()
' IQueryable implementation
Dim baseQuery = EntityQuery.CreateQuery(GetType(Product), anEntityManager)
Dim query2 = baseQuery.Where(p1.And(p2))
' can't call query2.ToList() because query2 is not an IQueryable<T>
Dim results As IEnumerable = anEntityManager.ExecuteQuery(query2)
' next line is required in order to
Dim products2 As IEnumerable(Of Product) = results.Cast(Of Product)()

Combine predicates with PredicateBuilder
Last modified on April 26, 2011 14:27
Contents
Two kinds of predicate
Why do we need the PredicateBuider?
PredicateBuilder APIs
PredicateBuilder examples
Debugging PredicateBuilder methods
Lazy typed PredicateDescriptions
Convert a PredicateDescription to a "predicate expression"
The IdeaBlade.Linq.PredicateBuilder provides the core functionality to build dynamic LINQ
Where clauses out of multiple predicates. This topic explores predicate combinations and
delves further into PredicateBuilder and PredicateDescription capabilities.


Two kinds of predicate
A predicate is a function that returns true or false for an item it evaluates. A query Where
clause takes a predicate that filters items to include in the query result.
Predicates come in two forms in DevForce queries.
an object of type Expression<Func<T, bool>>. This is referred to as a predicate expression.
an object that implements the DevForce IdeaBlade.Core.IPredicateDescription interface such
as IdeaBlade.Linq.PredicateDescription.
You use the predicate expression form when defining a LINQ query and you know the type
of object the predicate will evaluate. You use the IPredicateDescription form when you don't
know the type of object to filter at compile time.
Why do we need the PredicateBuider?
We need PredicateBuilder because combining predicates of either kind is hard in .NET. Let's
illustrate with two predicate expressions.
C#
Expression<Func<Customer, bool>> expr1 = (Customer c) => c.CompanyName.StartsWith("A");
Expression<Func<Customer, bool>> expr2 = (Customer c) => c.CompanyName.Contains("e");
VB
Dim expr1 As Expression(Of Func(Of Customer, Boolean)) = _
Function(c As Customer) c.CompanyName.StartsWith("A")
Dim expr2 As Expression(Of Func(Of Customer, Boolean)) = _
Function(c As Customer) c.CompanyName.Contains("e")
It's easy to use either of these expressions independently; it's not obvious how to combine
them.
C#
var query1 = myEntityManager.Customers.Where(expr1); // ok
var query2 = myEntityManager.Customers.Where(expr2); // ok
var queryBoth = myEntityManager.Customers.Where(expr1 && expr2) // BAD - won't compile.
VB
Dim query1 = myEntityManager.Customers.Where(expr1) ' ok
Dim query2 = myEntityManager.Customers.Where(expr2) ' ok
Dim queryBoth = myEntityManager.Customers.Where(expr1 AndAlso expr2) ' BAD - won't
compile.
The PredicateBuilder can combine two predicates into a third predicate; then we pass that
third predicate to the query's Where clause:
C#
var expr3 = PredicateBuilder.And(expr1, expr2);
var queryBoth = myEntityManager.Customers.Where(expr3); // this works
VB
Dim expr3 = PredicateBuilder.And(expr1, expr2)
Dim queryBoth = myEntityManager.Customers.Where(expr3) ' this works
Here's a more convenient syntax that uses PredicateBuilder's predicate expression extension
methods to do the same thing without mentioning PredicateBuilder explicitly:
C#
var expr3 = expr1.And(expr2);
var queryBoth = myEntityManager.Customers.Where(expr3); // this works
VB
Dim expr3 = expr1.And(expr2)
Dim queryBoth = myEntityManager.Customers.Where(expr3) ' this works
PredicateBuilder APIs
The PredicateBuilder is a static class with two kinds of static methods:
1. methods that take predicate expression parameters and return a predicate expression - the
strongly typed API.
2. methods that take IPredicateDescription parameters and return an IPredicateDescription -
the untyped API.
The two APIs mirror each other. We'll describe the strongly typed API involving predicate
expressions and assume confidently that you can extrapolate to the IPredicateDescription
methods.
Method Example
And PredicateBuilder.And(p1, p2, p3 .. pn)
Or PredicateBuilder.Or(p1, p2, p3 .. pn)
Not PredicateBuilder.Not(p1)
True PredicateBuilder.True<Product>()
False PredicateBuilder.False<Product>()
p = Predicate Expression, Expression<Func<T, bool>>, where 'T' is the type of the
evaluated item.
All combined predicates must have the same item type (e.g., Product).
The True() and False() methods return predicate expression constants that simply help you
jump-start your chaining of PredicateBuilder expressions ... as seen in the examples below.
Additional overloads of Or(), And(), and Not() are extension methods that make fluent
composition of predicates a little easier:
p1.Or(p2)
p1.And(p2)
p1.Not()
The parallel extension methods for IPredicateDescription are located in
DynamicQueryExtensions rather than PredicateBuilder.
PredicateBuilder examples
Here are some examples using the PredicateBuilder predicate expression methods:
C#
Expression<Func<Product, bool>> p1, p2, p3, p4, bigP;
// Sample predicate expressions
p1 = p => p.ProductName.Contains("Sir");
p2 = p => p.ProductName.Contains("Cajun");
p3 = p => p.ProductName.Contains("Louisiana");
p4 = p => p.UnitPrice > 20;
bigP = p1.Or(p2); // Name contains "Sir" or "Cajun"
bigP = p1.Or(p2).Or(p3); // Name contains any of the three
bigP = PredicateBuilder.Or(p1, p2, p3); // Name contains any of the 3
bigP = PredicateBuilder.Or(tests); // OR together some tests
bigP = p1.And(p4); // "Sir" and price is greater than 20
// Name contains "Cajun" and "Lousiana" and the price is greater than 20
bigP = PredicateBuilder.And(p2, p3, p4);
bigP = PredicateBuilder.And(tests); // AND together some tests
// Name contains either Sir or Louisiana AND price is greater than 20
bigP = p1.Or(p3).And(p4); //
bigP = PredicateBuilder.Not(p1); // Name does not contain "Sir"
bigP = PredicateBuilder.True<Product>().And(p1);// same as p1
bigP = PredicateBuilder.False<Product>().Or(p1);// same as p1
// Not useful
bigP = PredicateBuilder.True<Product>().Or(p1);// always true
bigP = PredicateBuilder.False<Product>().And(p1);// always false
VB
Dim p1 As Expression(Of Func(Of Product, Boolean)), p2 As Expression(Of _
Func(Of Product, Boolean)), p3 As Expression(Of Func(Of Product, Boolean)), _
p4 As Expression(Of Func(Of Product, Boolean)), bigP As Expression(Of _
Func(Of Product, Boolean))
' Sample predicate expressions
p1 = Function(p) p.ProductName.Contains("Sir")
p2 = Function(p) p.ProductName.Contains("Cajun")
p3 = Function(p) p.ProductName.Contains("Louisiana")
p4 = Function(p) p.UnitPrice > 20
bigP = p1.Or(p2) ' Name contains "Sir" or "Cajun"
bigP = p1.Or(p2).Or(p3) ' Name contains any of the three
bigP = PredicateBuilder.Or(p1, p2, p3) ' Name contains any of the 3
bigP = PredicateBuilder.Or(tests) ' OR together some tests
bigP = p1.And(p4) ' "Sir" and price is greater than 20
' Name contains "Cajun" and "Lousiana" and the price is greater than 20
bigP = PredicateBuilder.And(p2, p3, p4)
bigP = PredicateBuilder.And(tests) ' AND together some tests
' Name contains either "Sir" or "Louisiana" AND price is greater than 20
bigP = p1.Or(p3).And(p4)
bigP = PredicateBuilder.Not(p1) ' Name does not contain "Sir"
bigP = PredicateBuilder.True(Of Product)().And(p1) ' same as p1
bigP = PredicateBuilder.False(Of Product)().Or(p1) ' same as p1
' Not useful
bigP = PredicateBuilder.True(Of Product)().Or(p1) ' always true
bigP = PredicateBuilder.False(Of Product)().And(p1) ' always false
Debugging PredicateBuilder methods
Put a breakpoint on any of the "bigP" lines and ask the debugger to show you the result as a
string. Here is the Immediate Window output for
C# bigP = p1.Or(p3).And(p4);
VB bigP = p1.Or(p3).And(p4)
{p => ((p.ProductName.Contains("Sir") ||
p.ProductName.Contains("Louisiana")) && (p.UnitPrice > Convert(20)))}
Lazy typed PredicateDescriptions
We usually specify the item type when we create a PredicateDescription. That isn't strictly
necessary. We can postpone determining the query type until the PredicateDescription is used
in a query. For example:
C#
var p1 = new PredicateDescription("UnitPrice", FilterOperator.IsGreaterThanOrEqualTo, 24);
var p2 = new PredicateDescription("Discontinued", FilterOperator.IsEqualTo, true);
var p3 = p1.And(p2); //unit price >= 24 and discontinued.
VB
Dim p1 = New PredicateDescription("UnitPrice", FilterOperator.IsGreaterThanOrEqualTo, 24)
Dim p2 = New PredicateDescription("Discontinued", FilterOperator.IsEqualTo, True)
Dim p3 = p1.And(p2) ' unit price >= 24 and discontinued.
The variables p1, p2, p3 are well-defined but do not have embedded query types. They can be
used in any query for which they are appropriate, e.g.,
C#
var productQuery = mgr.Products.Where(p3);
var internationalProductQuery = mgr.InternationalProducts.Where(p3);
// but not
var customerQuery = mgr.Customers.Where(p3);
VB
Dim productQuery = mgr.Products.Where(p3)
Dim internationalProductQuery = mgr.InternationalProducts.Where(p3)
' but not
Dim customerQuery = mgr.Customers.Where(p3)
The customerQuery compiles but throws at runtime because Customer doesn't have a
UnitPrice or Discontinued property. The productQuery and internationalQuery will run
because these properties are defined for Product and InternationalProduct.
As a general rule it is best to embed the query type in the PredicateDescription when you
define it unless you have a compelling reason to do otherwise. Filtering on anonymous types
within a complex query is one such compelling reason.
Convert a PredicateDescription to a "predicate expression"
When a dynamic PredicateDescription has an embedded query type information, you can
convert it into a strongly typed predicate expression using the ToLambdaExpression()
method. Once converted, the expression is ready to use in a strongly-typed query, the kind of
query you typically write in an application. The following code illustrates:
C#
// p1 was the first PredicateDescription that filtered for UnitPrice >= 24
var exprFunc = (Expression<Func<Product, bool>>)p1.ToLambdaExpression();
var filterQuery = anEntityManager.Products.Where(exprFunc);
var results = anEntityManager.ExecuteQuery(filterQuery);
VB
' p1 was the first PredicateDescription that filtered for UnitPrice >= 24
Dim exprFunc = CType(p3.ToLambdaExpression(), Expression(Of Func(_
Of Product, Boolean)))
Dim filterQuery = _em1.Products.Where(exprFunc)
Dim results = _em1.ExecuteQuery(filterQuery)
This gambit is only possible when you can pass the PredicateDescription into compiled code
that knows the target type ... as happened here. Such occasions are rare but they occur and the
ToLambdaExpression() method is standing by when the opportunity to convert presents itself.

Create dynamic "OrderBy" clauses
Last modified on October 27, 2011 15:29
You can specify the "OrderBy" criteria dynamically with the I deaBlade.Linq.SortSelector
when you can't determine the sort order at compile time.
You create an instance of the SortSelector class by specifying the type of object to sort, the
property to sort, and its sort direction. The OrderBySelector extension method makes it easy
to use a SortSelector in a standard LINQ query you would otherwise have used OrderBy,
OrderByDescending, ThenBy or ThenByDescending. For example:
C#
var sort = new SortSelector(typeof(Customer), "Country", ListSortDirection.Descending);
var customers = myEntityManager.Customers.OrderBySelector(sort).ToList();

// compare with the strongly-typed LINQ equivalent
var customers = myEntityManager.Customers.OrderByDescending(c => c.Country).ToList();
VB
Dim sort = New SortSelector(GetType(Customer), "Country", ListSortDirection.Descending)
Dim customers = myEntityManager.Customers.OrderBySelector(sort).ToList()

' compare with the strongly-typed LINQ equivalent
Dim customers = myEntityManager.Customers.OrderByDescending(Function(c)
c.Country).ToList()
A single SortSelector instance can specify multiple sort properties, each with its own sort
direction. You add sort criteria with the ThenBy method.
C#
var sort = new SortSelector(typeof(Customer), "Country", ListSortDirection.Descending);
sort = sort.ThenBy("CompanyName"); // by default ListSortDirection is Ascending if not specified.
var customers = myEntityManager.Customers.OrderBySelector(sort).ToList();

// compare with the strongly-typed LINQ equivalent
var customers = myEntityManager.Customers
.OrderByDescending(c => c.Country)
.ThenBy(c => c.CompanyName)
.ToList();
VB
Dim sort = New SortSelector(GetType(Customer), "Country", ListSortDirection.Descending)
sort = sort.ThenBy("CompanyName") ' by default ListSortDirection is Ascending if not specified.
Dim customers = myEntityManager.Customers.OrderBySelector(sort).ToList()

' compare with the strongly-typed LINQ equivalent
Dim customers = myEntityManager.Customers
.OrderByDescending(Function(c) c.Country)
.ThenBy(Function(c) c.CompanyName)
.ToList()
SortSelectors can also be combined with an overload of the ThenBy method or with the static
Combine method.
C#
// create two SortSelectors
var sort1 = new SortSelector(typeof(Customer), "Country", ListSortDirection.Descending);
var sort2 = new SortSelector(typeof(Customer), "CompanyName");

// combine them using either of the following two mechanisms.
var sort = sort1.ThenBy(sort2);
// or
var sort = SortSelector.Combine(new[] { sort1, sort2 });
VB
' create two PropertySelectors
Dim sort1 = New SortSelector(GetType(Customer), _
"Country", ListSortDirection.Descending)
Dim sort2 = New SortSelector(GetType(Customer), "CompanyName")

' combine them using either of the following two mechanisms.
Dim sort = sort1.ThenBy(sort2)
' or
Dim sort = SortSelector.Combine( { sort1, sort2 })


The syntax and behavior of a SortSelector are similar to the PredicateDescription used in a Where
clause as described here and here. For example, you can delay specifying the type of entity to sort
until you actually use the SortSelector.
C#
// Type not specified; it is determined when used
var sort = new SortSelector("Country", ListSortDirection.Descending);
var customers = myEntityManager.Customers.OrderBySelector(sort).ToList();
VB
' Type not specified; it is determined when used
Dim sort = New SortSelector("Country", ListSortDirection.Descending)
Dim customers = myEntityManager.Customers.OrderBySelector(sort).ToList()
Such lazy-typing can be useful when sorting anonymous types.
PropertySortSelector is deprecated
The IdeaBlade.Linq.PropertySortSelector was the less-capable class for ordering query result
dynamically in versions of DevForce prior to v.6.1.0. That class has been deprecated in favor
of SortSelector and will be removed from the product at a future date.






Create dynamic "Select", "SelectMany" and "GroupBy" clauses
Last modified on October 27, 2011 15:29
Contents
Select examples
o Select into a dynamic type
o The DevForce dynamic type
o The memory footprint of dynamic types
SelectMany example
GroupBy example
PropertyProjectionSelector is deprecated
You can construct Select, SelectMany and GroupBy clauses dynamically with the
IdeaBlade.Linq.ProjectionSelector when you can't specify them at compile time.


The LINQ Select, SelectMany and GroupBy clauses change the shape of a query result.
Queries that uses these clauses are called "projections" and we refer to them as "projection
clauses" in the following discussion.
When you need to construct a projection query but you don't know the types involved at
compile time, you can create an instance of the ProjectionSelector class and pass in the type
information at runtime.
Select examples

When creating a ProjectionSelector class you specify the properties to select (AKA,
"project"). You can also specify the type of object to which the properties belong ... if you
know the type ... or delay type identification until you use the selector.
Consider a simple example in which we query for Customers and return ("project") their
CompanyNames. If we knew we were going to do this at compile time, we'd write:
C# var companyNames = anEntityManager.Customers.Select(c => c.CompanyName).ToList();
VB Dim companyNames = anEntityManager.Customers.Select(Function(c) c.CompanyName).ToList()
But we don't know. So we write a general purpose function, DoSelect, that is capable of
projecting an arbitrary property belonging to an arbitrary entity type. To see it in action, we
call it with the Customer type and specify the CompanyName type as before.
C#
public IEnumerable DoSelect(EntityManager manager, Type entityType, string propertyName) {
var selector = new ProjectionSelector(propertyName);

var rootQuery = EntityQuery.Create(entityType, manager);
var query = rootQuery.Select(selector); // selector learns its type from rootQuery
var results = query.Execute(); // synchronous query execution
return results;
}

// The company names of every Customer
var companyNames = DoSelect(anEntityManager, typeof(Customer), "CompanyName");
VB
Public Function DoSelect(ByVal manager As EntityManager, ByVal entityType As Type,
ByVal propertyName As String) As IEnumerable

Dim selector = New ProjectionSelector(propertyName)

Dim rootQuery = EntityQuery.Create(entityType, manager)
Dim query = rootQuery.Select(selector) ' selector learns its type from rootQuery
Dim results = query.Execute() ' synchronous query execution
Return results
End Function

' The company names of every Customer
Dim companyNames = DoSelect(anEntityManager, GetType(Customer), "CompanyName")
Any property of a class can be projected by passing in its property name, or as in the next
example, passing in a nested property name.
C#
// The company names of every Order's Customer
var companyNames = DoSelect(anEntityManager, typeof(Order), "Customer.CompanyName");
VB
' The company names of every Order's Customer
Dim companyNames = DoSelect(anEntityManager, GetType(Order), "Customer.CompanyName")
Select into a dynamic type
We can use the Select clause to project multiple values into a single instance of a DevForce
dynamic type (we explain dynamic types below). In our next example, we get a few Products,
find their related Category entities, and project two of the Category properties into a dynamic
type. For ease of exposition, we specify Product, Category and its properties in the code. If
you actually knew the types and properties at design time you'd use strongly typed LINQ
statements and wouldn't bother with the ProjectionSelector. We trust you appreciate our true
intention.
C#
IProjectionSelector selector = new ProjectionSelector("Category.Name", "CatName");
selector = selector.Combine("Category.Description", "CatDesc");

var rootQuery = EntityQuery.Create(typeof(Product), anEntityManager);
var query = rootQuery.Select(selector);
var results = query.Execute();
VB
Dim selector = New ProjectionSelector("Category.Name", "CatName") as IProjectionSelector
selector = selector.Combine("Category.Description", "CatDesc"))

Dim rootQuery = EntityQuery.Create(GetType(Product), anEntityManager)
Dim query = rootQuery.Select(selector)
Dim results = query.Execute()
A perhaps more graceful syntax, especially when there are many properties, might be:
C#
var selector = new AnonymousProjectionSelector()
.Combine("Category.Name", "CatName")
.Combine("Category.Description", "CatDesc");

var rootQuery = EntityQuery.Create(typeof(Product), anEntityManager);
var query = rootQuery.Select(selector);
var results = query.Execute();
VB
Dim selector = New AnonymousProjectionSelector()
.Combine("Category.Name", "CatName")
.Combine("Category.Description", "CatDesc")

Dim rootQuery = EntityQuery.Create(typeof(Product), anEntityManager)
var query = rootQuery.Select(selector)
Dim results = query.Execute()

This form draws proper attention to the AnonymousProjectionSelector and the use of the Combine
extension method to build up the properties of the projection.
The "CatName" and "CatDesc" arguments are the aliases for the projected nested properties;
they become the names of the two properties of the DevForce dynamic type objects returned
in the results.
Finally, a quite general projection function which suggests the potential for this approach:
C#
public IEnumerable DoSelect(
EntityManager manager, Type entityType, params string[] propertyNames)
{
var selector = new AnonymousProjectionSelector();
foreach (var name in propertyNames)
{
var alias = name.Replace(".", "_");
selector = selector.Combine(name, alias);
}

var rootQuery = EntityQuery.Create(entityType, manager);
var query = rootQuery.Select(selector); // selector learns its type from rootQuery
var results = query.Execute(); // synchronous query execution
return results;
}
VB
Public Function DoSelect(ByVal manager As EntityManager, _
ByVal entityType As Type, ByVal ParamArray propertyNames As String()) As IEnumerable

Dim selector = new AnonymousProjectionSelector()
For Each name As String In propertyNames
Dim alias = name.Replace(".", "_")
selector = selector.Combine(name, alias)
Next

Dim rootQuery = EntityQuery.Create(entityType, manager)
Dim query = rootQuery.Select(selector) ' selector learns its type from rootQuery
Dim results = query.Execute() ' synchronous query execution
Return results

End Function

The DevForce dynamic type
The DevForce dynamic type returned in query results may be treated exactly like a standard
.NET anonymous type. DevForce cannot return an actual .NET anonymous type because the
compiler insists that anonymous types be known at compile time. The dynamic types
DevForce creates are not defined until runtime. Therefore, DevForce dynamically creates a
type that has the same semantics as an anonymous type by emitting IL at runtime.
A DevForce dynamic type has one additional benefit: it is a public class which means that
Silverlight controls can bind to it. Silverlight controls can't bind to .NET anonymous classes
becauses they are declared internal.
You access properties of a dynamic type much as you would properties of a .NET anonymous
type as we see in the following two examples. The first makes use of the dynamic keyword
introduced in .NET 4.
C#
foreach (dynamic item in results) {
String categoryName = (String) item.CatName;
String categoryDescription = (String)item.CatDesc;
}
VB
For Each item As dynamic In results
Dim categoryName As String = CType(item.CatName, String)
Dim categoryDescription As String = CType(item.CatDesc, String)
Next item
The second uses the DevForce IdeaBlade.Core.AnonymousFns helper class to deconstruct a
dynamic type into an object array.
C#
var elementType = results.Cast<Object>().FirstOrDefault().GetType();
var items = AnonymousFns.DeconstructMany(results, false, elementType);

foreach (var item in items) {
String categoryName = (String) item[0];
String categoryDescription = (String)item[1];
}
VB
Dim elementType = results.Cast(Of Object)().FirstOrDefault().GetType()
Dim items = AnonymousFns.DeconstructMany(results, False, elementType)

For Each item In items
Dim categoryName As String = CType(item(0), String)
Dim categoryDescription As String = CType(item(1), String)
Next item
The memory footprint of dynamic types
Dynamic projections are convenient but should be used with care. Every .NET type definition
consumes memory that cannot be reclaimed by the .NET garbage collector. This is as true of
the dynamic types that DevForce creates as it is of .NET anonymous types. Queries that return
the same dynamic type "shape" - the same properties, of the same types, in the same order,
with the same names - are not a problem; dynamic type definitions are cached and a type
with matching shape is reused. But it's possible for client applications to create an endless
variety of dynamic type shapes.
While the amount of memory consumed by a single type is tiny and almost never an issue on
a single client machine, each of these types is also created on the EntityServer where the
query is executed. A long-running EntityServer might accumulate large numbers of distinct
dynamic type definitions. The server could run out of memory if it saw millions of different
anonymous types in which case you'll have to recycle the server periodically if this becomes a
problem. It's not a great risk but we felt we should mention it.
SelectMany example
A dynamic implementation of the LINQ SelectMany operation also makes use of the
ProjectionSelector. The following contrived example shows how to use SelectMany to get the
OrderDetails associated with the first five Products in the database. It relies upon a peculiar
function, DoSelectMany, that gets an arbitrary set of related entities from the first five
instance of some kind of entity.
C#
public IEnumerable DoSelectMany(
EntityManager manager, Type entityType, string propertyName)
{
var selector = new ProjectionSelector(propertyName);

var rootQuery = EntityQuery.Create(entityType, manager);
var query = rootQuery
.Take(5) // reduce the result size for exposition.
.SelectMany(selector);
var results = query.Execute();
return results;
}

var orderDetails =
DoSelectMany(anEntityManager, typeof(Product), "OrderDetails")
.Cast<OrderDetail>() // convert IEnumerable to IEnumerable<OrderDetails>
.ToList();
VB
Public Function DoSelectMany(ByVal manager As EntityManager, _
ByVal entityType As Type, ByVal propertyName As string) As IEnumerable

var selector = New ProjectionSelector(propertyName)

Dim rootQuery = EntityQuery.Create(entityType, mManager)
Dim query = rootQuery
.Take(2) ' reduce the result size for exposition.
.SelectMany(selector)
Dim results = query.Execute()
Return results

End Function

Dim orderDetails =
DoSelectMany(anEntityManager, GetType(Product), "OrderDetails")
.Cast<OrderDetail>() ' convert IEnumerable to IEnumerable<OrderDetails>
.ToList()
GroupBy example

A dynamic implementation of the LINQ GroupBy operation also makes use of the
ProjectionSelector. In the following example, the SimpleGroupBy function queries for every
instance of a given type and groups the results by one of the properties of that type.
C#
public IEnumerable SimpleGroupBy(EntityManager manager,
Type entityType, string groupByProperty)
{
var groupBy = new ProjectionSelector(groupByProperty, alias);

var query = EntityQuery.Create(entityType, manager)
.GroupBy(groupBy);
var result = manager.ExecuteQuery(query);
return result;
}

// Static equivalent: anEntityManager.Products.GroupBy(_ => _.Category.CategoryName);
var result = SimpleGroupBy(anEntityManager,
typeof(Product), "Category.CategoryName");

var productGrps = result.Cast<IGrouping<String, Product>>().ToList();
VB
Public Function SimpleGroupBy(ByVal manager As EntityManager,
ByVal entityType As Type,ByVal groupByProperty As String) _
As IEnumerable

Dim groupBy = new ProjectionSelector(groupByProperty, alias)

Dim query = EntityQuery.Create(entityType, manager)
.GroupBy(groupBy)
Dim result = manager.ExecuteQuery(query)
Return result
End Function

' Static equivalent: anEntityManager.Products.GroupBy(Function(_) _.Category.CategoryName)
Dim result = SimpleGroupBy(anEntityManager,
GetType(Product), "Category.CategoryName")

Dim productGrps = result.Cast(Of IGrouping(Of String, Product))().ToList()

PropertyProjectionSelector is deprecated
The IdeaBlade.Linq.PropertyProjectionSelector is now obsolete, having been superseded by
the ProjectionSelector. I





































Query using property navigation
Querying using property navigation is a convenient syntax for accessing data from related
entities.
Consider these familiar scenarios:
Get the line items (OrderDetails) of an order
Get the name of the order's parent customer
Get the parent customer's other orders
In DevForce you might write:
anOrder.OrderDetails
anOrder.Customer.CompanyName
anOrder.Customer.Orders
In each case, we want information (OrderDetails, Customers) related to a single entity
(Order). The desired information exists somewhere in the entitys object graph the network
of other entities that are related to it. Property navigation helps us traverse the network to
reach related entities.
The third example shows how you can chain navigation properties together. The statement
anOrder.Customer.Orders navigates from a particular Order up to its parent Customer and
then down to all of the parent Customer's other Orders. We call this "walking the object
graph".
There are two kinds of navigation property:
1. Reference Navigation returns at most a single entity, typically a "parent" entity as in
anOrder.Customer.
2. Collection Navigation returns a list of related entities, typically the "children" of this
entity as in aCustomer.Orders and anOrder.OrderDetails.
Navigation properties and data retrieval
Any time a navigation property is accessed, DevForce needs to determine whether to try to
fetch the related entity or entities from the backend datastore or to use previously retrieved
data. In general, the first time any navigation property on an entity is accessed, data will be
retrieved from the database and all subsequent attempts to access the property will use the
local cache. Navigation properties and data retrieval can be modified in several ways.


Navigation properties
Every navigation property on an entity has a corresponding EntityReferenceBase that in turn has an
IsLoaded property that is settable. This may be set on a per entity/per navigation property basis. For
example to force the next access of myCustomer.Orders to go to the database the following code
would be used.
C# Customer.PropertyMetadata.Orders.GetEntityReference(myCustomer).IsLoaded = false;
VB Customer.PropertyMetadata.Orders.GetEntityReference(myCustomer).IsLoaded = False
Every navigation property has its default 'loading' behavior determined by a
ReferenceStrategy that may be set on the appropriate EntityProperty. This is a global setting
for this property across all entities. For example to force every access of any Customer's
Orders property to go to the database and to have the results of this navigation overwrite any
local changes the following code would be used.
C#
Customer.PropertyMetadata.Orders.ReferenceStrategy =
new EntityReferenceStrategy(EntityReferenceLoadStrategy.Load,
MergeStrategy.OverwriteChanges);
VB
Customer.PropertyMetadata.Orders.ReferenceStrategy = _
New EntityReferenceStrategy(EntityReferenceLoadStrategy.Load, _
MergeStrategy.OverwriteChanges)
As shown in the example above, a ReferenceStrategy is itself is made up of a
EntityReferenceLoadStrategy and a MergeStrategy. The EntityReferenceLoadStrategy
determines under what conditions data should be 'loaded' ( i.e. retrieved from the database)
and the MergeStrategy determines how that data, if loaded, gets merged into the local entity
cache.
LoadStrategy Meaning
Lazy
first access to the property should go to the database; subsequent accesses should
use the local cache
Load for every access always try to load from the database
DoNotLoad
never try to load from the database; property access always looks in cache. You can
load the entities manually as described below.
The default LoadStrategy is Lazy; the default MergeStrategy is PreserveChanges. These
concepts are also discussed under the Entity cache and Entity metadata topics.
Loaded state
The ReferenceStrategy governs the behavior of a navigation property for all instances of the
entity type. You can tweak the current state of a particular entity's navigation property. For
example, you can force the "cust" Customer entity to act as if its orders have already been
loaded into cache:
C#
Customer.PropertyMetadata.Orders
.GetEntityReference(cust)
.IsLoaded = true;
VB
Customer.PropertyMetadata.Orders _
.GetEntityReference(cust) _
.IsLoaded = True
If you didn't know the entity type or property name at compile time, you could write a general
function to do this. The pertinent statement would be something like:
C#
anEntity.EntityAspect.EntityMetadata
.NavigationProperties
.First(p => p.Name == somePropertyName)
.GetEntityReference(anEntity)
.IsLoaded = true;
VB
anEntity.EntityAspect.EntityMetadata _
.NavigationProperties _
.First(Function(p) p.Name = somePropertyName) _
.GetEntityReference(anEntity) _
.IsLoaded = True
This statement would have the same effect as before if anEntity == cust and
somePropertyName == "Orders".
Force loading
If you set an entity type's LoadStrategy to DoNotLoad as we did above, you'll have to
manually manage the loading of the property's data. Sometimes you want to force a
navigation property to refresh. Here's one way to force a (re)load of the example customer's
orders:
C#
Customer.PropertyMetadata.Orders
.GetEntityReference(cust)
.Load(MergeStrategy.PreserveChanges);
VB
Customer.PropertyMetadata.Orders _
.GetEntityReference(cust) _
.Load(MergeStrategy.PreserveChanges)
The navigation property load operation runs asynchronously in Silverlight, synchronously
elsewhere.
It may be easier simply to query cust's orders directly from the database after which
cust.Orders will find them in cache.
Parent-child navigation properties
Last modified on March 22, 2011 11:56
So far weve considered only navigation properties that return a single entity. Navigation
properties can return many entities. The myOrder.OrderDetails navigation property, for
example, returns the many line items of a single order.
Navigation properties that return multiple entities are sometimes termed parent->child or
principal->dependent properties. In these cases, the property belongs to the parent entity
such as Order and it returns child entities such as OrderDetail entities.
The navigation property returns child entities in a RelatedEntityList<T> collection. For
example, the Order.OrderDetails property returns its OrderDetail children in a concrete
collection, RelatedEntityList<OrderDetail>.
A brief example
I write and run the following statements and learn that there are three line items in the
collection owned by anOrder:
C#
Order anOrder = _em1.Orders.FirstOrNullEntity();
RelatedEntityList<OrderDetail> lineItems = anOrder.OrderDetails;
VB
Dim anOrder As Order = _em1.Orders.FirstOrNullEntity()
Dim lineItems As RelatedEntityList(Of OrderDetail)=anOrder.OrderDetails
We decide to increase the quantity ordered for the first OrderDetail as follows.
C#
var firstItem = lineItems[0];
firstItem.Quantity = 10;
VB
Dim firstItem As OrderDetail = lineItems(0)
firstItem.Quantity = 10

Adding and Removing Related Objects
Add()
The Add() method takes a parameter of the type contained by the collection (e.g., an Order).
C#
Order anOrder = new Order();
anOrder.OrderDate = DateTime.Today;
anOrder.FreightCost = Convert.ToDecimal(999.99);
anEmployee.Orders.Add(anOrder);
VB
Dim anOrder As New Order()
anOrder.OrderDate = Date.Today
anOrder.FreightCost = Convert.ToDecimal(999.99)
anEmployee.Orders.Add(anOrder)
Invoking Add() adds the supplied item to the collection. If the relation between the parent and
child types is 1-to-many and the supplied item is currently associated with a different parent,
then Add() simultaneously removes it from the corresponding collection of the other parent.
The equivalent result on table rows in a relational database is that the child entitys foreign
key value is changed.
Note that, in the above snippet, we did not need to set the SalesRep property of the new Order to
the Employee whom we wanted to become its parent:
C# // anOrder.SalesRep = anEmployee; //don't need this; Add() will handle it
VB anOrder.SalesRep = anEmployee '' don't need this; Add() will handle it
Invocation of the Add() method on anEmployee.Orders produced the equivalent result.
Remove()
Remove() also takes a parameter of the type contained by the collection. It dissociates the
indicated instance from the collections parent. Speaking again of the equivalent result on
table rows in a relational database, the child entitys foreign key value is set to null.
C# anEmployee.Orders.Remove(anOrder);
VB anEmployee.Orders.Remove(anOrder)
Note that while Remove unassigns the Order from the target Employee, removing it from the
collection returned by the navigation property, it does not remove it from the cache or mark it
for deletion. If you want the Order removed from the cache or deleted from the back-end
datastore, you must order those actions separately by calling the Orders
EntityAspect.Remove()or EntityAspect.Delete() methods, as appropriate.
Add() and Remove () on many-to-many navigation properties
You can also use Add() and Remove () on many-to-many navigation collections generated by
the Entity Data Model. You get these in your Entity Data Model when two entities are linked
by a many-to-many linking table that has "no payload"; that is, no columns other than the two
foreign keys (which also form a composite primary key). An example would be an Employee
linked to a Territory by means of an EmployeeTerritory table whose composite primary key
consists of the two foreign keys EmployeeId and TerritoryId, and which has no other
columns.
When you have such an association, invoking Add() on the many-to-many navigation property
creates (in the EntityManager cache) the necessary linking object in the EntitySet for the
linking objects. Note that those objects are not exposed in the conceptual model, and are never
manipulated directly by you. Remove() marks as deleted the linking object that formerly
connected the two entities in the many-to-many relationship. Both changes the insertion of a
new linking object or the deletion of an existing one are propagated to the back-end data
store upon the execution of SaveChanges() on the governing EntityManager.
Adding and removing items in custom-coded many-to-many navigation properties
You can (and probably will) also have in your model many-to-many associations involving
linking entities that do have payload. (For example, in the NorthwindIB database, Order links
Employees (who act as sales reps) to Customers in a many-to-many relationship.) For these
cases, you should add and remove elements to the m-to-m collection (e.g.,
anEmployee.Customers) by inserting or deleting instances of the linking entity. Since that
linking entity is probably significant in its own right (again consider an Order), it likely has
properties that need their values set at creation time in any case.
For example, the following code will have the indirect effect of adding a new Customer to the
Customers collection of anEmployee, but only if the Order being added is for a Customer with
which anEmployee is not already linked through some other Order. Otherwise, aCustomer is
already in anEmployees Customers collection.
(Note: Create is a static method on the Order partial class that the developer extends)
C#
// May add a Customer to anEmployees Customers collection
anOrder = Order.Create(_entityManager, aCustomer, anOrderDate);
anEmployee.Orders.Add(anOrder);
VB
' May add a Customer to anEmployees Customers collection
anOrder = Order.Create(_entityManager, aCustomer, anOrderDate)
anEmployee.Orders.Add(anOrder)
Similarly, the following code will have the indirect effect of removing aCustomer from the
Customers collection of anEmployee, but only if anEmployee has no other Orders for
aCustomer. If she does, then aCustomer will remain in her Customers collection.
C#
// May remove a Customer from anEmployees Customers collection
anOrder.EntityAspect.Delete();
VB
' May remove a Customer from anEmployees Customers collection
anOrder.EntityAspect.Delete()

Asynchronous navigation properties
Applicable to Silverlight primarily
Because all data retrieval and save operations in Silverlight are required to be asynchronous,
navigation properties must be able to execute asynchronously as well. This means that
they must be able to return their results within lambdas or callback methods that will execute
at an indeterminate time in the future. What is unusual about this process is that property
navigation by its nature must also return an immediate result. If the query needs to execute
asynchronously, then this immediate result must have some way of indicating that it is not
(yet) a real result and that the 'real' result is coming. This introduces the concepts of a
PendingEntity and a PendingEntityList. Consider the following code:
(Note that this example has been written to run in a desktop environment, instead of Silverlight, in
order to more easily make use of the Console.WriteLine to illustrate the timing of events)
C#
public void NavigationBasicAsynchronous() {
_em1.UseAsyncNavigation = true; // not needed in SILVERLIGHT
var query = _em1.Orders.Where(o => o.OrderID == 10248);
_query.ExecuteAsync(GotOrder);
}

private void GotOrder(EntityQueryOperation<Order> args) {
if (args.Error != null) {
Console.WriteLine(args.Error.Message);
} else {
// Retrieve a single related entity using a scalar navigation property
Order targetOrder = (Order)args.Results.ToList()[0];
Console.WriteLine("Order: {0}", targetOrder.OrderID.ToString());
targetOrder.Customer.EntityAspect.PendingEntityResolved +=
Customer_PendingEntityResolved;
Customer aCustomer = targetOrder.Customer;
Console.WriteLine("Customer (from GotOrders): {0}", aCustomer.CompanyName);
// Retrieve a collection of related entities using a
//collection navigation properties
targetOrder.OrderDetails.PendingEntityListResolved +=
OrderDetails_PendingEntityListResolved;
}
}

void Customer_PendingEntityResolved(object sender,
PendingEntityResolvedEventArgs e) {
Customer customer = (Customer)e.ResolvedEntity;
Console.WriteLine("Customer (from Customer_PendingEntityResolved): {0}",
customer.CompanyName);
}

void OrderDetails_PendingEntityListResolved(object sender,
PendingEntityListResolvedEventArgs<OrderDetail> e) {
Console.WriteLine("OrderDetails retrieved: {0}", e.ResolvedEntities.Count);
}

private void PromptToContinue() {
Console.WriteLine();
Console.WriteLine("Press ENTER to continue...");
Console.ReadLine();
}
VB
Public Sub NavigationBasicAsynchronous()
ResetEntityManager(_em1)
_em1.UseAsyncNavigation = True
Dim query As IEntityQuery(Of Order) = _
_em1.Orders.Where(Function(o) o.OrderID = 10248)
_em1.ExecuteQueryAsync(Of Order)(query, AddressOf GotOrder, Nothing)
PromptToContinue()
End Sub

Private Sub GotOrder(ByVal args As EntityQueryOperation(Of Order))
If args.Error IsNot Nothing Then
Console.WriteLine(args.Error.Message)
Else
' Retrieve a single related entity using a scalar navigation property
Dim targetOrder As Order = CType(args.Results.ToList()(0), Order)
Console.WriteLine("Order: {0}", targetOrder.OrderID.ToString())
AddHandler targetOrder.Customer.EntityAspect.PendingEntityResolved, _
AddressOf Customer_PendingEntityResolved
Dim aCustomer As Customer = targetOrder.Customer
Console.WriteLine("Customer (from GotOrders): {0}", aCustomer.CompanyName)
' Retrieve a collection of related entities
' using a collection navigation property
AddHandler targetOrder.OrderDetails.PendingEntityListResolved, _
AddressOf OrderDetails_PendingEntityListResolved
Console.WriteLine("OrderDetails retrieved: {0}", _
targetOrder.OrderDetails.ToList().Count)
End If
End Sub

Private Sub Customer_PendingEntityResolved(ByVal sender As Object, _
ByVal e As PendingEntityResolvedEventArgs)
Dim customer As Customer = CType(e.ResolvedEntity, Customer)
Console.WriteLine( _
"Customer (from Customer_PendingEntityResolved): {0}", customer.CompanyName)
End Sub

Private Sub OrderDetails_PendingEntityListResolved(ByVal sender _
As Object, ByVal e As PendingEntityListResolvedEventArgs(Of OrderDetail))
Console.WriteLine("OrderDetails retrieved: {0}", e.ResolvedEntities.Count)
End Sub

Private Sub ResetEntityManager(ByVal em As EntityManager)
em.Clear()
em.UseAsyncNavigation = False
End Sub
In the methods first statement we set the UseAsyncNavigation property of the EntityManager
to true. This step would be unnecessary in a Silverlight application, as true is the default,
(and only) setting for that property in that environment. But the above code could run in both
Silverlight and non-Silverlight environments.
Now consider the statements that retrieve the Order. For a couple of reasons, we cant simply
say this
C# Order anOrder = _em1.Orders.FirstOrNullEntity();
VB Dim anOrder As Order = _em1.Orders.FirstOrNullEntity()
, because the attempt to execute the above statement would fail in a Silverlight app with a
message to the effect that Queries in Silverlight must be executed asynchronously. So to
get our single Order, we need to submit a query with a condition that retrieves the desired
Order, as you saw in the main snippet. That query must, of course, also be submitted
asynchronously, and a callback method provided to process the results. To retrieve a scalar
result, such as First(), Single(), Count(), Sum() and others, you may also use the
AsScalarAsync() extension on IEntityQuery<T> to convert your query into a scalar query
which can be executed asynchronously.
C#
...
var query = _em1.Orders.Where(o => o.OrderID == 10248);
query.ExecuteAsync(GotOrder);
...
}

private void GotOrder(EntityQueryOperation<Order> args) {
if (args.Error != null) {
Console.WriteLine(args.Error.Message);
}
else {
// Retrieve a single related entity using a scalar navigation property
Order targetOrder = (Order)args.Results.ToList()[0];
Console.WriteLine("Order: {0}", targetOrder.OrderID.ToString());
}
}
VB
...
Dim query As IEntityQuery(Of Order) = _
_em1.Orders.Where(Function(o) o.OrderID = 10248)
_em1.ExecuteQueryAsync(Of Order)(query, AddressOf GotOrder, Nothing)
...
End Sub

Private Sub GotOrder(ByVal args As EntityQueryOperation(Of Order))
If args.Error IsNot Nothing Then
Console.WriteLine(args.Error.Message)
Else
' Retrieve a single related entity using a scalar navigation property
Dim targetOrder As Order = CType(args.Results.ToList()(0), Order)
Console.WriteLine("Order: {0}", targetOrder.OrderID.ToString())
End If
End Sub
In this case, since were using the primary key to fetch our Order, we know that args.Result
will contain at most one entity; so we simply cast it into an Order and proceed.
To get the Customer related to that Order (refer back to the full snippet), we set up a handler
for the PendingEntityResolved event of the Customer navigation property,
targetOrder.Customer. Then to initiate the asynchronous retrieval of that customer, we
reference it in a code statement:
C# Customer aCustomer = targetOrder.Customer;
VB Dim aCustomer As Customer = targetOrder.Customer
We included a call to Console.WriteLine() immediately following the above statement just to
show that the desired Customer simply isnt going to be available at that point. The statement
will write out a blank for the Customers CompanyName. Where we will get results is in the
Customer_PendingEntityResolved handler:
C#
void Customer_PendingEntityResolved(object sender,
PendingEntityResolvedEventArgs e) {
Customer customer = (Customer)e.ResolvedEntity;
Console.WriteLine("Customer (from Customer_PendingEntityResolved): {0}",
customer.CompanyName);
}
VB
Private Sub Customer_PendingEntityResolved(ByVal sender As Object, _
ByVal e As PendingEntityResolvedEventArgs)
Dim customer As Customer = CType(e.ResolvedEntity, Customer)
Console.WriteLine("Customer (from Customer_PendingEntityResolved): {0}", _
customer.CompanyName)
End Sub
Asynchronous collection navigation properties
For navigation properties that return a collection, DevForce provides a
PendingEntityListResolved event, similar to the PendingEntityResolved event weve just
discussed:
C#
private void GotOrder(EntityQueryOperation<Order> args) {
// Retrieve a collection of related entities usin
// a collection navigation property
Order targetOrder = (Order)args.Results.ToList()[0];
targetOrder.OrderDetails.PendingEntityListResolved +=
new EventHandler<PendingEntityListResolvedEventArgs<OrderDetail>>(
OrderDetails_PendingEntityListResolved);
}

void OrderDetails_PendingEntityListResolved(object sender,
PendingEntityListResolvedEventArgs<OrderDetail> e) {
Console.WriteLine("OrderDetails retrieved: {0}", e.ResolvedEntities.Count);
}
VB
Private Sub GotOrder(ByVal args As EntityQueryOperation(Of Order))
' Retrieve a collection of related entities usin
' a collection navigation property
Dim targetOrder As Order = CType(args.Results.ToList()(0), Order)
AddHandler targetOrder.OrderDetails.PendingEntityListResolved, _
AddressOf OrderDetails_PendingEntityListResolved
End Sub

Private Sub OrderDetails_PendingEntityListResolved(ByVal sender As Object, _
ByVal e As PendingEntityListResolvedEventArgs(Of OrderDetail))
Console.WriteLine("OrderDetails retrieved: {0}", e.ResolvedEntities.Count)
End Sub
When we run the full snippet, the code displays the following results in the Console window:

The output line Press ENTER to continue.. comes from the utility method
PromptToContinue(), which executes synchronously and immedately. Then we see reflected
back the OrderID of the retrieved Order; the non-existent CompanyName of the not-yet-
retrieved, related Customer; the CompanyName of the Customer written after its retrieval by
the Customer_PendingEntityResolved callback method; and the display of OrderDetails
retrieved, written by the OrderDetails_PendingEntityListResolved method.
Using an anonymous method for navigation property callback
If youre working in C#, you can also use inline, anonymous methods for your
ExecuteQueryAsync() callbacks:
C#
public void NavigationBasicAsynchronousAnonymousCallback() {
_em1.UseAsyncNavigation = true;
IEntityQuery<Order> query = _em1.Orders.Where(o => o.OrderID == 10248);
_em1.ExecuteQueryAsync<Order>(
query, // IEntityQuery<Order>
(args) => { // AsyncCompletedCallbac
Console.WriteLine("Order: {0}", // "
((Order)args.Results.ToList()[0]).OrderID); // "
}, // "
null // UserState object
);
PromptToContinue();
}
VB
Public Sub NavigationBasicAsynchronousAnonymousCallback()
_em1.UseAsyncNavigation = True
Dim query As IEntityQuery(Of Order) = _
_em1.Orders.Where(Function(o) o.OrderID = 10248)
_em1.ExecuteQueryAsync(Of Order)(query, Sub(args) _
Console.WriteLine("Order: {0}", (CType(args.Results.ToList()(0), _
Order)).OrderID), Nothing)
' UserState object - " - " - "
PromptToContinue()
End Sub
These are handy when the logic to be included in the callback isnt too involved.
Deferred retrieval
When does the entitymanager fetch myOrders line items from the data source?
We might have written DevForce to fetch them automatically when it fetched myOrder. But if
DevForce were to get the line items automatically, why stop there? It could get the customer
for the order, the sales rep for the order, and the products for each line item.
Those are just the immediate neighbors. It could get the customers headquarter address, the
sales reps address and manager, and each products manufacturer. If it continued like this, it
might fetch most of the database.
Retrieving the entire graph is obviously wasteful and infeasible. How often do we want to
know the manager of the sales rep who booked the order? Clearly we have to prune the object
graph. But where do we prune? How can we know in advance which entities we will need and
which we can safely exclude?
We cannot know. Fortunately, we dont have to know. We dont have to know if we can be
certain of continuous connection to the data source. If we expect the application to run offline,
well have to anticipate the related entities well need and pre-fetch them. Well get to this
issue later. We keep it simple. We use an entity query to get the root entities (such as
myOrder). Then we use entity navigation to retrieve neighboring related entities as we need
them.
This just-in-time approach is called deferred retrieval (also known as "lazy instantiation",
"lazy loading", "Just-In-Time [JIT] data retrieval", and so on).

Missing objects and the null entity
A reference navigation property and some scalar queries return the null entity when there is
no entity to return. The null entity (aka, the nullo) is a special version of an entity class that
represents the missing object.


In principle, every Order should have a parent Customer. What if a particular noCustOrder
doesn't have a parent Customer? What should its Customer navigation property return?
Should it return null (Nothing in VB)? Then the statement
noCustOrder.Customer.CompanyName will throw a NullReferenceException because the null
value doesn't have a CompanyName property.
Should we wrap every reference navigation in a giant try/catch block? Or should we follow
every entity navigation with a test for null? That might be worse than catching an exception.
In some situations - in UI code for example - it is difficult to check whether noCustOrder has
a Customer, let alone do something about it.
Fortunately an entity reference navigation neither returns a null value nor throws an
exception. Instead, when the entitymanager can't find the Customer, it returns the Customer
null entity.
The null entity
The null entity represents the "entity not found". The null entity (known informally as the
nullo) is a sentinel object that looks and behaves, for the most part, like a real entity instance.
In most respects it is a real entity
it has a specific type (e.g., Customer)
it has the properties, methods, and events of its type.
it belongs to an EntityManager
The null entity has four important differences:
You can tell its the null entity because noCustOrder.Customer.EntityAspect.IsNullEntity
returns true
You cannot set a nullo property.
You cannot create, delete or save a nullo.
There is only one nullo per type in a given EntityManager; you can't have two Customer
nullos in the same EntityManager.
Actions returning a nullo
Among the ways to get a null entity are
a reference navigation that cannot find the parent entity
a scalar query that fails to find the requested entity
ask the EntityManager for it
Reference navigation
A reference navigation property returns a single entity. The Order.Customer is a reference
navigation property returning the order's parent Customer. Because noCustOrder lacks a
parent Customer, the statement noCustOrder.Customer returns a Customer nullo.
We don't worry about null entities with collection navigations. A collection navigation
property returns a list. The list is never null. It is an empty list if there are no related entities.
The statement emptyOrder.OrderDetails returns an empty list of OrderDetail.
Scalar query
A scalar query returns a single object. In the following example, the developer executes a
scalar query, requesting that the query return either the first entity found or the null entity if
there is no match. There is no Customer with a zero ID.
C#
cust = manager.Customers
.Where(c => c.CustomerID == 0) // doesn't exist
.FirstOrNullEntity();
VB
cust = (From c in manager.Customers _
Where c = 0 _' doesn't exist
Select c) _
.FirstOrNullEntity()
Note that query would have returned null - the cust value would be null - if the developer
executed the query with FirstOrDefault.
Get from manager
Although you can't create a nullo, you can ask an EntityManager to give you the nullo of a
particular type.
C# nullo = manager.GetNullEntity<Customer>(); // the Customer nullo
VB nullo = manager.GetNullEntity(Of Customer)() ' the Customer nullo
Nullos belong to an EntityManager
A null entity always belongs to a particular EntityManager, the same EntityManager as the
entity which produced it. The nullo from noCustOrder.Customer belongs to noCustOrder's
manager.
While there can be only one Customer nullo per EntityManager there can be two nullo
Customer instances ... if there are two EntityManagers.
The requirement that a null entity belong to cache has an unexpected implication. What if the
noCustOrder is not in cache ... if it is detached?
Then the statement noCustOrder.Customer returns the null value. You won't get a nullo from
a detached entity. A detached entity can't return a nullo because a null entity always belongs
to a particular EntityManager and a detached entity doesn't have an EntityManager. DevForce
doesn't know what EntityManager to use. All it can do is return null.
The default nullo
Every entity class defines its own null entity.
You don't have to do anything special. By default, its simple data properties return the default
value for the property's type. An int returns 0. A string returns the empty string. A property
returning a native .NET object type returns a null object of that type; a nullable int returns
null.
Navigation properties are different.
A nullo's reference navigation property returns another nullo. The statement
noCustOrder.Customer.Region returns the Region nullo. This makes it safe to chain nullos as
in noCustOrder.Customer.Region.Country.CountryName.
A collection navigation property returns an empty collection. The statement
noCustOrder.Customer.Orders returns an empty list of Orders.
ComplexType properties return a real ComplexType object with property values like a nullo.
Configure the nullo
The CompanyName property of the Customer nullo returns an empty string. Suppose you
prefer that it return a canned value such as "N/A" or "[none]". You can change the property
values of a nullo if you don't like the defaults by overriding the UpdateNullEntity method in
the partial class.
Build queries dynamically
LINQ expressions are strongly typed and static. They are easy to compose when you know
the type of thing you want to query at compile time. But they are difficult to create if you
don't know the type until the application runs. Many applications let the user specify the entity
type to retrieve, the criteria to filter with, the properties to sort and group by. DevForce
dynamic query building components help you build and execute LINQ queries on the fly
based on information supplied at runtime.


The problem
"LINQ" stands for "Language Integrated Query". LINQ is designed to be written in the
same manner as other code, rubbing shoulders with procedural statements in the body of your
application source files. C# and Visual Basic are statically typed languages so the main
pathway for writing LINQ queries is to compose them statically as strongly typed query
objects that implement the IQueryable<T> interface. Standard LINQ queries, and almost of
the LINQ examples in the DevForce Resource Center, are static and strongly typed. Here is a
typical example:
C#
IQueryable<Customer> customers = _myEntityManager.Customers;
var query = customers.Where(c => c.CompanyName = "Acme");
VB
Dim customers As IQueryable(Of Customer) = _myEntityManager.Customers
Dim query = customers.Where(Function(c) c.CompanyName = "Acme")
The _myEntityManager.Customers expression returns an instance of a query object that
implements IQueryable<Customer>. The strongly typed nature of the expression is what
allows IntelliSense and the compiler to interpret the remainder of the statement.
What if 'T' (Customer in this case) is not known until runtime; from a compiler perspective we
no longer have an IQueryable<T> but have instead just an IQueryable. And IQueryable,
unfortunately, does not offer any of the extension methods that we think of a standard LINQ;
in other words, no Where, Select, GroupBy, OrderBy, Any, Count etc, methods.
How do we write a query when we don't have the type available at runtime?
C#
var typeToQuery = typeof(Customer);
IQueryable<???> someCollection = << HOW DO I CREATE AN IQUERYABLE OF "typeToQuery"?>> ;
var query = somecollection.Where( << HOW DO I COMPOSE A LAMBDA EXPRESSION WITHOUT A
COMPILE TIME TYPE >> );
VB
Dim typeToQuery = GetType(Customer)
IQueryable(Of ???) someCollection = << HOW DO I CREATE AN IQUERYABLE OF
"typeToQuery"?>>
Dim query = somecollection.Where(<< HOW DO I COMPOSE A LAMBDA EXPRESSION WITHOUT A
COMPILE TIME TYPE >>)
A second issue can occur even if we know the type of the query but we have a number of
'where conditions' or predicates, that need to be combined. For example
C#
Expression<Func<Customer, bool>> expr1 = (Customer c) => c.CompanyName.StartsWith("A");
Expression<Func<Customer, bool>> expr2 = (Customer c) => c.CompanyName.StartsWith("B");
VB
Dim expr1 As Expression(Of Func(Of Customer, Boolean)) = _
Function(c As Customer) c.CompanyName.StartsWith("A")
Dim expr2 As Expression(Of Func(Of Customer, Boolean)) = _
Function(c As Customer) c.CompanyName.StartsWith("B")
It turns out that we can use either of these expressions independently, but it isn't obvious how
to combine them.
C#
var query1 = myEntityManager.Customers.Where(expr1); // ok
var query2 = myEntityManager.Customers.Where(expr1); // ok
var queryBoth = myEntityManager.Customers.Where(expr1 && expr2) // BAD - won't compile.
VB
Dim query1 = myEntityManager.Customers.Where(expr1) ' ok
Dim query2 = myEntityManager.Customers.Where(expr1) ' ok
Dim queryBoth = myEntityManager.Customers.Where(expr1 AndAlso expr2) ' BAD - won't
compile.
The ESQL option
You can construct queries on the fly using DevForce "pass-thru" Entity SQL (ESQL). ESQL
queries are strings that look like standard SQL, differing primarily (and most obviously) in
their references to entity types and properties rather than tables and columns. You can build
ESQL queries by concatenating strings that incorporate the runtime query critieria you
gleaned from user input.
Most developers prefer to construct LINQ queries with DevForce for two reasons:
1. Building syntactically correct ESQL strings can be more difficult to do correctly than writing
DevForce dynamic queries. The dynamic query approach affords a greater degree of compiler
syntax checking and the structure of the query is more apparent. You often know most of the
query at design time; when only some of the query is variable you can mix the statically
typed LINQ statements with the dynamic clauses ... as described in the topic detail.
2. ESQL queries must be sent to and processed on the server. You cannot apply ESQL queries to
the local entity cache. LINQ queries, on the other hand, can be applied to the database, to
the cache, or to both. This is as true of dynamic LINQ queries as it is of static queries. For
many developers this is reason enough to prefer LINQ to ESQL.
DevForce dynamic query building
In order to accomplish this the following pages discuss
how to dynamically construct a 'root' query.
how to dynamically construct and combine predicates ( LINQ Where clauses).
how to dynamically construct sorting conditions ( LINQ OrderBy clauses.
how to dynamically construct projections and groupings ( LINQ Select,SelectMany and
GroupBy clauses).
how to dynamically construct most other LINQ query methods.


Create a completely dynamic query
Last modified on April 26, 2011 15:17
Contents
EntityQuery.Create
LINQ methods where no IQueryable<T> exists
Most of the queries created using DevForce will be instances of some query subclass that
implements IQueryable<T>. However, there will be cases where we will not be able to
determine "T" until runtime. A "completely dynamic" query is one where we do not know the
type "T" of the query at compile time. Because these queries cannot implement
IQueryable<T> they will instead implement the IQueryable interface.


EntityQuery.Create
The static EntityQuery.Create is a non-generic method that creates a new query for a specified
type. Here is a function that employs EntityQuery.Create to produce a query that retrieves
every instance of a type:
C#
public EntityQuery GetAll(Type entityType, EntityManager manager)
{
return EntityQuery.Create(entityType, manager);
}
VB
Public Function GetAll(ByVal entityType As Type, ByVal manager as EntityManager) As
EntityQuery
Return EntityQuery.Create(entityType, manager)
End Function
It's a contrived example but you can imagine something like it supporting an application
feature that lets users pick the type of entity to retrieve from a list. We use it to retrieve
Products and compare this approach with the strongly typed LINQ statement that does the
same thing ... when you know that you are always getting Products:
C#
var queryType = typeof(Product); // the type picked by the user
EntityQuery query1 = GetAll(queryType, anEntityManager);
EntityQuery<Product> query2 = anEntityManager.Products;
VB
Dim queryType = GetType(Product) ' the type picked by the user
Dim query1 As EntityQuery = GetAll(queryType, anEntityManager)
Dim query2 As EntityQuery(Of Product) = anEntityManager.Products
These two queries are identical from the standpoint of how they get executed and what they
return. The critical difference is that the compiler can't know the type of the query returned in
the first case and therefore must return an EntityQuery (which implements IQueryable and
ITypedQuery) instead of EntityQuery<T> (which implements IQueryable<T>).
This has three ramifications:
Completely dynamic queries typically derive from EntityQuery which implements IQueryable
and ITypedQuery.
These queries must be executed either with the IEntityQuery.Execute extension method or
the EntityManager.Execute method; you can't use ToList().
Such queries return IEnumerable results instead of IEnumerable<T>.
The following example illustrates these points:
C#
// IQueryable implementation
var query1 = EntityQuery.Create(typeof(Product), anEntityManager);
// can't call query1.ToList() because query1 is not an IQueryable<T>
IEnumerable results = query1.Execute();
// Have to cast to work with Products
IEnumerable<Product> products1 = results.Cast<Product>();

// IQueryable<T> implementation
var query2 = anEntityManager.Products;
IEnumerable<Product> products2 = query2.ToList();
VB
' IQueryable implementation
Dim query1 = EntityQuery.Create(GetType(Product), anEntityManager)
' can't call query1.ToList() because query1 is not an IQueryable<T>
Dim results As IEnumerable = query1.Execute()
' Have to cast to work with Products
Dim products1 As IEnumerable(Of Product) = results.Cast(Of Product)()

' IQueryable<T> implementation
Dim query2 = anEntityManager.Products
Dim products2 As IEnumerable(Of Product) = query2.ToList()
LINQ methods where no IQueryable<T> exists

LINQ queries, as defined in standard .NET depend on the IQueryable<T> and
IEnumerable<T> interfaces. Because a "completely dynamic" query only implements the
IQueryable interface there is no way to implement the "standard" LINQ operators. However,
DevForce does provide a substitute.
DevForce implements a separate set of extension methods that have the same names as the
standard LINQ operators but operate on instances of objects that only implement IQueryable
instead of IQueryable<T>. ( See IdeaBlade.Linq.QueryableExtensions). That covers many of
the familiar LINQ operators and immediate execution methods.
Some extension methods require further refinment to operate specifically on instances of
DevForce EntityQuery (as opposed to EntityQuery<T>. These methods may be found in
IdeaBlade.EntityModel.EntityQueryExtensions along side the other EntityQuery extension
methods. They are distinguishable by their first parameter which is of type
ITypedEntityQuery.
The ITypedEntityQuery interface describes an EntityQuery that is actually an EntityQuery<T> but the
type "T" will not be known until runtime and is therefore not available at compile time. This is not
something that a developer will usually ever have to concern himself/herself with.
The EntityQueryExtensions include the following methods that return an ITypedEntityQuery.
EntityQueryExtensions.Where
EntityQueryExtensions.OrderBySelector
EntityQueryExtensions.Select
EntityQueryExtensions.SelectMany
EntityQueryExtensions.GroupBy
EntityQueryExtensions.Take
EntityQueryExtensions.Skip
EntityQueryExtensions.Cast
EntityQueryExtensions.OfType
as well as the following immediate execution methods that take an ITypedEntityQuery and
return a scalar result.
EntityQueryExtensions.All
EntityQueryExtensions.Any
EntityQueryExtensions.Contains
EntityQueryExtensions.Count
An overload of EntityQueryExtensions.AsScalarAsync also extends ITypedEntityQuery so you
can call the asynchronous scalar functions {First..., Count, etc.).
These overloads differ from the standard LINQ overloads in that none of them involve
parameters that are Expression<Func<T, ...>. This is again a ramification of the fact that the
generic type "T" is not available at compile time for these methods. These methods instead
take either a PredicateDescription, SortSelector, or ProjectionSelector in place of the strongly
typed Expression<...>.
Create dynamic "Where" clauses
The need for the ability to create a dynamic where clause occurs fairly frequently in
applications that need to filter data based on a users input. In these cases you don't really
know ahead of time what properties a user is going to want to query or what the conditions
of the query are likely to be. In fact, you may not even know the type that you will be
querying for until runtime. So you will need to be able to compose the query based on the
inputs determined at runtime.


Flavors of dynamic where clauses

Ideally, when building a query we want to specify as little dynamically as we have to. The
less dynamic a query is the better the compile time checking and intellisense will be for the
query. Everything depends upon what we know and when we know it. Do we know the type
of the query at compile time but need to wait until runtime to determine the properties to be
queried and the conditions regarding these properties? Or do we not even know the type of the
query until runtime?
Whatever the case, the IdeaBlade.Linq.PredicateBuilder and the
IdeaBlade.Linq.PredicateDescription classes are the tools used to deal with compile time
uncertainty. As we review the PredicateBuilder API, you will see both typed and untyped
overloads for most methods in order to support both compile and runtime scenarios.
Whats a predicate?
A LINQ where clause is intimately tied to the concept of a "predicate". So what is a predicate
and how does it relate to a LINQ where clause.
A predicate is a function that evaluates an expression and returns true or false. The code
fragment...
C# p.ProductName.Contains("Sir")
VB p.ProductName.Contains("Sir")
...is a predicate that examines a product and returns true if the products ProductName
contains the Sir string.
The CLR type of the predicate in our example is:
C# Func<Product, bool>
VB Func(Of Product, Boolean)
Which we can generalize to:
C# Func<T, bool>
VB Func(Of T, Boolean)
This is almost what we need in order to build a LINQ where clause. The LINQ Where
extension method is defined as follows:
C#
public static IQueryable<T> Where<TSource>(
this IQueryable<T> source1, Expression<Func<T,bool>> predicate)
VB
public static IQueryable(Of T) Where(Of TSource) _
(Me IQueryable(Of T) source1, Expression(Of Func(Of T,Boolean)) predicate)
Note that the "predicate" parameter above is
C# Expression<Func<T, bool>>
VB Expression(Of Func(Of T, Boolean))
When we refer to the idea that a "predicate" is needed in order to build a LINQ where clause,
what we really mean is that we need to build a "predicate expression", or a Expression that is
resolvable to a simple predicate.
Create a Where clause with two predicates
The snippet below comprises two statements, each of which uses PredicateBuilder.Make to
create a PredicateDescription representing a single predicate (filter criteria).
C#
PredicateDescription p1 = PredicateBuilder.Make(typeof(Product), "UnitPrice",
FilterOperator.IsGreaterThanOrEqualTo, 24);
PredicateDescription p2 = PredicateBuilder.Make(typeof(Product), "Discontinued",
FilterOperator.IsEqualTo, true);
VB
Dim p1 As PredicateDescription = PredicateBuilder.Make(GetType(Product), "UnitPrice", _
FilterOperator.IsGreaterThanOrEqualTo, 24)
Dim p2 As PredicateDescription = PredicateBuilder.Make(GetType(Product), "Discontinued", _
FilterOperator.IsEqualTo, True)
A new query can then be composed and executed by an EntityManager as usual:
C#
var query = anEntityManager.Products.Where(p1.And(p2))
// The above query is the same as:
//var queryb = anEntityManager.Products.Where(p => p.UnitPrice > 24 && p.Discontinued);
VB
Dim query = anEntityManager.Products.Where(p1.And(p2))
' The above query is the same as:
'var queryb = anEntityManager.Products.Where(p => p.UnitPrice > 24 && p.Discontinued);
We could have combined the individual PredicateDescriptions into another
PredicateDescription variable:
C#
CompositePredicateDescription p3 = p1.And(p2);
var query = anEntityManager.Products.Where(p3);
VB
Dim p3 As CompositePredicateDescription = p1.And(p2)
Dim query = anEntityManager.Products.Where(p5)
Learn more about combining predicates with PredicateBuilder and PredicateDescription
classes.
Completely dynamic query
The Where clause in the previous examples were still applied to a strongly typed (non-
dynamic) IQueryable<Product> implementation. To be more precise, the query root was of
type IEntityQuery<Product>.
What if we didn't know we were querying for Product at compile type? We'd know the type at
runtime but we didn't know it as we wrote the code. We could use the
EntityQuery.CreateQuery factory method and pass it the runtime type. CreateQuery returns a
nominally-untyped EntityQuery object.
C#
var queryType = typeof(Product); // imagine this was passed in at runtime.
var baseQuery = EntityQuery.CreateQuery(queryType , anEntityManager);
var query = baseQuery.Where(p1.And(p2));
VB
Dim queryType = GetType(Product) ' imagine this was passed in at runtime.
Dim baseQuery = EntityQuery.CreateQuery(queryType , anEntityManager)
Dim query = baseQuery.Where(p1.And(p2))
The EntityQuery result of CreateQuery implements ITypedEntityQuery. The Where clause in
this example made use of the ITypedEntityQuery extension method instead of the
IQueryable<T> extension method:
C#
public static ITypedEntityQuery Where(this ITypedEntityQuery source, IPredicateDescription
predicateDescription);
VB
Public Shared ITypedEntityQuery Where(Me ITypedEntityQuery source, _
IPredicateDescription predicateDescription)
The query that will be executed is exactly the same regardless of which extension method is
used. Both queries are Product queries. The critical difference is that the compiler can't
determine the type of the query in the second case. That's why it resolved to a query typed as
ITypedEntityQuery, which implements IQueryable, instead of IEntityQuery<T> which
implements IQueryable<T>.
There are two ramifications:
Completely dynamic queries, those typed as ITypedEntityQuery, must be executed with one
of the EntityManager.Execute methods instead of ToList().
The compiler declares that the type of the dynamic query execution result is IEnumerable
instead of IEnumerable<T>.
The following example illustrates:
C#
// IQueryable<T> implementation
var query1 = anEntityManager.Products.Where(p3);
IEnumerable<Product> products1 = query1.ToList();
// IQueryable implementation
var baseQuery = EntityQuery.CreateQuery(typeof(Product), anEntityManager);
var query2 = baseQuery.Where(p1.And(p2));
// can't call query2.ToList() because query2 is not an IQueryable<T>
IEnumerable results = anEntityManager.ExecuteQuery(query2);
// next line is required in order to
IEnumerable<Product> products2 = results.Cast<Product>();
VB
' IQueryable<T> implementation
Dim query1 = anEntityManager.Products.Where(p3)
Dim products1 As IEnumerable(Of Product) = query1.ToList()
' IQueryable implementation
Dim baseQuery = EntityQuery.CreateQuery(GetType(Product), anEntityManager)
Dim query2 = baseQuery.Where(p1.And(p2))
' can't call query2.ToList() because query2 is not an IQueryable<T>
Dim results As IEnumerable = anEntityManager.ExecuteQuery(query2)
' next line is required in order to
Dim products2 As IEnumerable(Of Product) = results.Cast(Of Product)()
Combine predicates with PredicateBuilder
The IdeaBlade.Linq.PredicateBuilder provides the core functionality to build dynamic LINQ
Where clauses out of multiple predicates. This topic explores predicate combinations and
delves further into PredicateBuilder and PredicateDescription capabilities.


Two kinds of predicate
A predicate is a function that returns true or false for an item it evaluates. A query Where
clause takes a predicate that filters items to include in the query result.
Predicates come in two forms in DevForce queries.
an object of type Expression<Func<T, bool>>. This is referred to as a predicate expression.
an object that implements the DevForce IdeaBlade.Core.IPredicateDescription interface such
as IdeaBlade.Linq.PredicateDescription.
You use the predicate expression form when defining a LINQ query and you know the type
of object the predicate will evaluate. You use the IPredicateDescription form when you don't
know the type of object to filter at compile time.
Why do we need the PredicateBuider?
We need PredicateBuilder because combining predicates of either kind is hard in .NET. Let's
illustrate with two predicate expressions.
C#
Expression<Func<Customer, bool>> expr1 = (Customer c) => c.CompanyName.StartsWith("A");
Expression<Func<Customer, bool>> expr2 = (Customer c) => c.CompanyName.Contains("e");
VB
Dim expr1 As Expression(Of Func(Of Customer, Boolean)) = _
Function(c As Customer) c.CompanyName.StartsWith("A")
Dim expr2 As Expression(Of Func(Of Customer, Boolean)) = _
Function(c As Customer) c.CompanyName.Contains("e")
It's easy to use either of these expressions independently; it's not obvious how to combine
them.
C#
var query1 = myEntityManager.Customers.Where(expr1); // ok
var query2 = myEntityManager.Customers.Where(expr2); // ok
var queryBoth = myEntityManager.Customers.Where(expr1 && expr2) // BAD - won't compile.
VB
Dim query1 = myEntityManager.Customers.Where(expr1) ' ok
Dim query2 = myEntityManager.Customers.Where(expr2) ' ok
Dim queryBoth = myEntityManager.Customers.Where(expr1 AndAlso expr2) ' BAD - won't
compile.
The PredicateBuilder can combine two predicates into a third predicate; then we pass that
third predicate to the query's Where clause:
C#
var expr3 = PredicateBuilder.And(expr1, expr2);
var queryBoth = myEntityManager.Customers.Where(expr3); // this works
VB
Dim expr3 = PredicateBuilder.And(expr1, expr2)
Dim queryBoth = myEntityManager.Customers.Where(expr3) ' this works
Here's a more convenient syntax that uses PredicateBuilder's predicate expression extension
methods to do the same thing without mentioning PredicateBuilder explicitly:
C#
var expr3 = expr1.And(expr2);
var queryBoth = myEntityManager.Customers.Where(expr3); // this works
VB
Dim expr3 = expr1.And(expr2)
Dim queryBoth = myEntityManager.Customers.Where(expr3) ' this works
PredicateBuilder APIs
The PredicateBuilder is a static class with two kinds of static methods:
1. methods that take predicate expression parameters and return a predicate expression - the
strongly typed API.
2. methods that take IPredicateDescription parameters and return an IPredicateDescription -
the untyped API.
The two APIs mirror each other. We'll describe the strongly typed API involving predicate
expressions and assume confidently that you can extrapolate to the IPredicateDescription
methods.
Method Example
And PredicateBuilder.And(p1, p2, p3 .. pn)
Or PredicateBuilder.Or(p1, p2, p3 .. pn)
Not PredicateBuilder.Not(p1)
True PredicateBuilder.True<Product>()
False PredicateBuilder.False<Product>()
p = Predicate Expression, Expression<Func<T, bool>>, where 'T' is the type of the
evaluated item.
All combined predicates must have the same item type (e.g., Product).
The True() and False() methods return predicate expression constants that simply help you
jump-start your chaining of PredicateBuilder expressions ... as seen in the examples below.
Additional overloads of Or(), And(), and Not() are extension methods that make fluent
composition of predicates a little easier:
p1.Or(p2)
p1.And(p2)
p1.Not()
The parallel extension methods for IPredicateDescription are located in
DynamicQueryExtensions rather than PredicateBuilder.
PredicateBuilder examples
Here are some examples using the PredicateBuilder predicate expression methods:
C#
Expression<Func<Product, bool>> p1, p2, p3, p4, bigP;
// Sample predicate expressions
p1 = p => p.ProductName.Contains("Sir");
p2 = p => p.ProductName.Contains("Cajun");
p3 = p => p.ProductName.Contains("Louisiana");
p4 = p => p.UnitPrice > 20;
bigP = p1.Or(p2); // Name contains "Sir" or "Cajun"
bigP = p1.Or(p2).Or(p3); // Name contains any of the three
bigP = PredicateBuilder.Or(p1, p2, p3); // Name contains any of the 3
bigP = PredicateBuilder.Or(tests); // OR together some tests
bigP = p1.And(p4); // "Sir" and price is greater than 20
// Name contains "Cajun" and "Lousiana" and the price is greater than 20
bigP = PredicateBuilder.And(p2, p3, p4);
bigP = PredicateBuilder.And(tests); // AND together some tests
// Name contains either Sir or Louisiana AND price is greater than 20
bigP = p1.Or(p3).And(p4); //
bigP = PredicateBuilder.Not(p1); // Name does not contain "Sir"
bigP = PredicateBuilder.True<Product>().And(p1);// same as p1
bigP = PredicateBuilder.False<Product>().Or(p1);// same as p1
// Not useful
bigP = PredicateBuilder.True<Product>().Or(p1);// always true
bigP = PredicateBuilder.False<Product>().And(p1);// always false
VB
Dim p1 As Expression(Of Func(Of Product, Boolean)), p2 As Expression(Of _
Func(Of Product, Boolean)), p3 As Expression(Of Func(Of Product, Boolean)), _
p4 As Expression(Of Func(Of Product, Boolean)), bigP As Expression(Of _
Func(Of Product, Boolean))
' Sample predicate expressions
p1 = Function(p) p.ProductName.Contains("Sir")
p2 = Function(p) p.ProductName.Contains("Cajun")
p3 = Function(p) p.ProductName.Contains("Louisiana")
p4 = Function(p) p.UnitPrice > 20
bigP = p1.Or(p2) ' Name contains "Sir" or "Cajun"
bigP = p1.Or(p2).Or(p3) ' Name contains any of the three
bigP = PredicateBuilder.Or(p1, p2, p3) ' Name contains any of the 3
bigP = PredicateBuilder.Or(tests) ' OR together some tests
bigP = p1.And(p4) ' "Sir" and price is greater than 20
' Name contains "Cajun" and "Lousiana" and the price is greater than 20
bigP = PredicateBuilder.And(p2, p3, p4)
bigP = PredicateBuilder.And(tests) ' AND together some tests
' Name contains either "Sir" or "Louisiana" AND price is greater than 20
bigP = p1.Or(p3).And(p4)
bigP = PredicateBuilder.Not(p1) ' Name does not contain "Sir"
bigP = PredicateBuilder.True(Of Product)().And(p1) ' same as p1
bigP = PredicateBuilder.False(Of Product)().Or(p1) ' same as p1
' Not useful
bigP = PredicateBuilder.True(Of Product)().Or(p1) ' always true
bigP = PredicateBuilder.False(Of Product)().And(p1) ' always false
Debugging PredicateBuilder methods
Put a breakpoint on any of the "bigP" lines and ask the debugger to show you the result as a
string. Here is the Immediate Window output for
C# bigP = p1.Or(p3).And(p4);
VB bigP = p1.Or(p3).And(p4)
{p => ((p.ProductName.Contains("Sir") ||
p.ProductName.Contains("Louisiana")) && (p.UnitPrice > Convert(20)))}
Lazy typed PredicateDescriptions
We usually specify the item type when we create a PredicateDescription. That isn't strictly
necessary. We can postpone determining the query type until the PredicateDescription is used
in a query. For example:
C#
var p1 = new PredicateDescription("UnitPrice", FilterOperator.IsGreaterThanOrEqualTo, 24);
var p2 = new PredicateDescription("Discontinued", FilterOperator.IsEqualTo, true);
var p3 = p1.And(p2); //unit price >= 24 and discontinued.
VB
Dim p1 = New PredicateDescription("UnitPrice", FilterOperator.IsGreaterThanOrEqualTo, 24)
Dim p2 = New PredicateDescription("Discontinued", FilterOperator.IsEqualTo, True)
Dim p3 = p1.And(p2) ' unit price >= 24 and discontinued.
The variables p1, p2, p3 are well-defined but do not have embedded query types. They can be
used in any query for which they are appropriate, e.g.,
C#
var productQuery = mgr.Products.Where(p3);
var internationalProductQuery = mgr.InternationalProducts.Where(p3);
// but not
var customerQuery = mgr.Customers.Where(p3);
VB
Dim productQuery = mgr.Products.Where(p3)
Dim internationalProductQuery = mgr.InternationalProducts.Where(p3)
' but not
Dim customerQuery = mgr.Customers.Where(p3)
The customerQuery compiles but throws at runtime because Customer doesn't have a
UnitPrice or Discontinued property. The productQuery and internationalQuery will run
because these properties are defined for Product and InternationalProduct.
As a general rule it is best to embed the query type in the PredicateDescription when you
define it unless you have a compelling reason to do otherwise. Filtering on anonymous types
within a complex query is one such compelling reason.
Convert a PredicateDescription to a "predicate expression"
When a dynamic PredicateDescription has an embedded query type information, you can
convert it into a strongly typed predicate expression using the ToLambdaExpression()
method. Once converted, the expression is ready to use in a strongly-typed query, the kind of
query you typically write in an application. The following code illustrates:
C#
// p1 was the first PredicateDescription that filtered for UnitPrice >= 24
var exprFunc = (Expression<Func<Product, bool>>)p1.ToLambdaExpression();
var filterQuery = anEntityManager.Products.Where(exprFunc);
var results = anEntityManager.ExecuteQuery(filterQuery);
VB
' p1 was the first PredicateDescription that filtered for UnitPrice >= 24
Dim exprFunc = CType(p3.ToLambdaExpression(), Expression(Of Func(_
Of Product, Boolean)))
Dim filterQuery = _em1.Products.Where(exprFunc)
Dim results = _em1.ExecuteQuery(filterQuery)
This gambit is only possible when you can pass the PredicateDescription into compiled code
that knows the target type ... as happened here. Such occasions are rare but they occur and the
ToLambdaExpression() method is standing by when the opportunity to convert presents itself.
Create dynamic "OrderBy" clauses
Last modified on April 26, 2011 16:13
You can specify the "OrderBy" criteria dynamically with the I deaBlade.Linq.SortSelector
when you can't determine the sort order at compile time.
You create an instance of the SortSelector class by specifying the type of object to sort, the
property to sort, and its sort direction. The OrderBySelector extension method makes it easy
to use a SortSelector in a standard LINQ query you would otherwise have used OrderBy,
OrderByDescending, ThenBy or ThenByDescending. For example:
C#
var sort = new SortSelector(typeof(Customer), "Country", ListSortDirection.Descending);
var customers = myEntityManager.Customers.OrderBySelector(sort).ToList();

// compare with the strongly-typed LINQ equivalent
var customers = myEntityManager.Customers.OrderByDescending(c => c.Country).ToList();
VB
Dim sort = New SortSelector(GetType(Customer), "Country", ListSortDirection.Descending)
Dim customers = myEntityManager.Customers.OrderBySelector(sort).ToList()

' compare with the strongly-typed LINQ equivalent
Dim customers = myEntityManager.Customers.OrderByDescending(Function(c)
c.Country).ToList()
A single SortSelector instance can specify multiple sort properties, each with its own sort
direction. You add sort criteria with the ThenBy method.
C#
var sort = new SortSelector(typeof(Customer), "Country", ListSortDirection.Descending);
sort = sort.ThenBy("CompanyName"); // by default ListSortDirection is Ascending if not specified.
var customers = myEntityManager.Customers.OrderBySelector(sort).ToList();

// compare with the strongly-typed LINQ equivalent
var customers = myEntityManager.Customers
.OrderByDescending(c => c.Country)
.ThenBy(c => c.CompanyName)
.ToList();
VB
Dim sort = New SortSelector(GetType(Customer), "Country", ListSortDirection.Descending)
sort = sort.ThenBy("CompanyName") ' by default ListSortDirection is Ascending if not specified.
Dim customers = myEntityManager.Customers.OrderBySelector(sort).ToList()

' compare with the strongly-typed LINQ equivalent
Dim customers = myEntityManager.Customers
.OrderByDescending(Function(c) c.Country)
.ThenBy(Function(c) c.CompanyName)
.ToList()
SortSelectors can also be combined with an overload of the ThenBy method or with the static
Combine method.
C#
// create two SortSelectors
var sort1 = new SortSelector(typeof(Customer), "Country", ListSortDirection.Descending);
var sort2 = new SortSelector(typeof(Customer), "CompanyName");

// combine them using either of the following two mechanisms.
var sort = sort1.ThenBy(sort2);
// or
var sort = SortSelector.Combine(new[] { sort1, sort2 });
VB
' create two PropertySelectors
Dim sort1 = New SortSelector(GetType(Customer), _
"Country", ListSortDirection.Descending)
Dim sort2 = New SortSelector(GetType(Customer), "CompanyName")

' combine them using either of the following two mechanisms.
Dim sort = sort1.ThenBy(sort2)
' or
Dim sort = SortSelector.Combine( { sort1, sort2 })


The syntax and behavior of a SortSelector are similar to the PredicateDescription used in a Where
clause as described here and here. For example, you can delay specifying the type of entity to sort
until you actually use the SortSelector.
C#
// Type not specified; it is determined when used
var sort = new SortSelector("Country", ListSortDirection.Descending);
var customers = myEntityManager.Customers.OrderBySelector(sort).ToList();
VB
' Type not specified; it is determined when used
Dim sort = New SortSelector("Country", ListSortDirection.Descending)
Dim customers = myEntityManager.Customers.OrderBySelector(sort).ToList()
Such lazy-typing can be useful when sorting anonymous types.
PropertySortSelector is deprecated
The IdeaBlade.Linq.PropertySortSelector was the less-capable class for ordering query result
dynamically in versions of DevForce prior to v.6.1.0. That class has been deprecated in favor
of SortSelector and will be removed from the product at a future date.
Create dynamic "Select", "SelectMany" and "GroupBy" clauses
You can construct Select, SelectMany and GroupBy clauses dynamically with the
IdeaBlade.Linq.ProjectionSelector when you can't specify them at compile time.


The LINQ Select, SelectMany and GroupBy clauses change the shape of a query result.
Queries that uses these clauses are called "projections" and we refer to them as "projection
clauses" in the following discussion.
When you need to construct a projection query but you don't know the types involved at
compile time, you can create an instance of the ProjectionSelector class and pass in the type
information at runtime.
Select examples

When creating a ProjectionSelector class you specify the properties to select (AKA,
"project"). You can also specify the type of object to which the properties belong ... if you
know the type ... or delay type identification until you use the selector.
Consider a simple example in which we query for Customers and return ("project") their
CompanyNames. If we knew we were going to do this at compile time, we'd write:
C# var companyNames = anEntityManager.Customers.Select(c => c.CompanyName).ToList();
VB Dim companyNames = anEntityManager.Customers.Select(Function(c) c.CompanyName).ToList()
But we don't know. So we write a general purpose function, DoSelect, that is capable of
projecting an arbitrary property belonging to an arbitrary entity type. To see it in action, we
call it with the Customer type and specify the CompanyName type as before.
C#
public IEnumerable DoSelect(EntityManager manager, Type entityType, string propertyName) {
var selector = new ProjectionSelector(propertyName);

var rootQuery = EntityQuery.Create(entityType, manager);
var query = rootQuery.Select(selector); // selector learns its type from rootQuery
var results = query.Execute(); // synchronous query execution
return results;
}

// The company names of every Customer
var companyNames = DoSelect(anEntityManager, typeof(Customer), "CompanyName");
VB
Public Function DoSelect(ByVal manager As EntityManager, ByVal entityType As Type,
ByVal propertyName As String) As IEnumerable

Dim selector = New ProjectionSelector(propertyName)

Dim rootQuery = EntityQuery.Create(entityType, manager)
Dim query = rootQuery.Select(selector) ' selector learns its type from rootQuery
Dim results = query.Execute() ' synchronous query execution
Return results
End Function

' The company names of every Customer
Dim companyNames = DoSelect(anEntityManager, GetType(Customer), "CompanyName")
Any property of a class can be projected by passing in its property name, or as in the next
example, passing in a nested property name.
C#
// The company names of every Order's Customer
var companyNames = DoSelect(anEntityManager, typeof(Order), "Customer.CompanyName");
VB
' The company names of every Order's Customer
Dim companyNames = DoSelect(anEntityManager, GetType(Order), "Customer.CompanyName")
Select into a dynamic type
We can use the Select clause to project multiple values into a single instance of a DevForce
dynamic type (we explain dynamic types below). In our next example, we get a few Products,
find their related Category entities, and project two of the Category properties into a dynamic
type. For ease of exposition, we specify Product, Category and its properties in the code. If
you actually knew the types and properties at design time you'd use strongly typed LINQ
statements and wouldn't bother with the ProjectionSelector. We trust you appreciate our true
intention.
C#
IProjectionSelector selector = new ProjectionSelector("Category.Name", "CatName");
selector = selector.Combine("Category.Description", "CatDesc");

var rootQuery = EntityQuery.Create(typeof(Product), anEntityManager);
var query = rootQuery.Select(selector);
var results = query.Execute();
VB
Dim selector = New ProjectionSelector("Category.Name", "CatName") as IProjectionSelector
selector = selector.Combine("Category.Description", "CatDesc"))

Dim rootQuery = EntityQuery.Create(GetType(Product), anEntityManager)
Dim query = rootQuery.Select(selector)
Dim results = query.Execute()
A perhaps more graceful syntax, especially when there are many properties, might be:
C#
var selector = new AnonymousProjectionSelector()
.Combine("Category.Name", "CatName")
.Combine("Category.Description", "CatDesc");

var rootQuery = EntityQuery.Create(typeof(Product), anEntityManager);
var query = rootQuery.Select(selector);
var results = query.Execute();
VB
Dim selector = New AnonymousProjectionSelector()
.Combine("Category.Name", "CatName")
.Combine("Category.Description", "CatDesc")

Dim rootQuery = EntityQuery.Create(typeof(Product), anEntityManager)
var query = rootQuery.Select(selector)
Dim results = query.Execute()

This form draws proper attention to the AnonymousProjectionSelector and the use of the Combine
extension method to build up the properties of the projection.
The "CatName" and "CatDesc" arguments are the aliases for the projected nested properties;
they become the names of the two properties of the DevForce dynamic type objects returned
in the results.
Finally, a quite general projection function which suggests the potential for this approach:
C#
public IEnumerable DoSelect(
EntityManager manager, Type entityType, params string[] propertyNames)
{
var selector = new AnonymousProjectionSelector();
foreach (var name in propertyNames)
{
var alias = name.Replace(".", "_");
selector = selector.Combine(name, alias);
}

var rootQuery = EntityQuery.Create(entityType, manager);
var query = rootQuery.Select(selector); // selector learns its type from rootQuery
var results = query.Execute(); // synchronous query execution
return results;
}
VB
Public Function DoSelect(ByVal manager As EntityManager, _
ByVal entityType As Type, ByVal ParamArray propertyNames As String()) As IEnumerable

Dim selector = new AnonymousProjectionSelector()
For Each name As String In propertyNames
Dim alias = name.Replace(".", "_")
selector = selector.Combine(name, alias)
Next

Dim rootQuery = EntityQuery.Create(entityType, manager)
Dim query = rootQuery.Select(selector) ' selector learns its type from rootQuery
Dim results = query.Execute() ' synchronous query execution
Return results

End Function

The DevForce dynamic type
The DevForce dynamic type returned in query results may be treated exactly like a standard
.NET anonymous type. DevForce cannot return an actual .NET anonymous type because the
compiler insists that anonymous types be known at compile time. The dynamic types
DevForce creates are not defined until runtime. Therefore, DevForce dynamically creates a
type that has the same semantics as an anonymous type by emitting IL at runtime.
A DevForce dynamic type has one additional benefit: it is a public class which means that
Silverlight controls can bind to it. Silverlight controls can't bind to .NET anonymous classes
becauses they are declared internal.
You access properties of a dynamic type much as you would properties of a .NET anonymous
type as we see in the following two examples. The first makes use of the dynamic keyword
introduced in .NET 4.
C#
foreach (dynamic item in results) {
String categoryName = (String) item.CatName;
String categoryDescription = (String)item.CatDesc;
}
VB
For Each item As dynamic In results
Dim categoryName As String = CType(item.CatName, String)
Dim categoryDescription As String = CType(item.CatDesc, String)
Next item
The second uses the DevForce IdeaBlade.Core.AnonymousFns helper class to deconstruct a
dynamic type into an object array.
C#
var elementType = results.Cast<Object>().FirstOrDefault().GetType();
var items = AnonymousFns.DeconstructMany(results, false, elementType);

foreach (var item in items) {
String categoryName = (String) item[0];
String categoryDescription = (String)item[1];
}
VB
Dim elementType = results.Cast(Of Object)().FirstOrDefault().GetType()
Dim items = AnonymousFns.DeconstructMany(results, False, elementType)

For Each item In items
Dim categoryName As String = CType(item(0), String)
Dim categoryDescription As String = CType(item(1), String)
Next item
The memory footprint of dynamic types
Dynamic projections are convenient but should be used with care. Every .NET type definition
consumes memory that cannot be reclaimed by the .NET garbage collector. This is as true of
the dynamic types that DevForce creates as it is of .NET anonymous types. Queries that return
the same dynamic type "shape" - the same properties, of the same types, in the same order,
with the same names - are not a problem; dynamic type definitions are cached and a type
with matching shape is reused. But it's possible for client applications to create an endless
variety of dynamic type shapes.
While the amount of memory consumed by a single type is tiny and almost never an issue on
a single client machine, each of these types is also created on the EntityServer where the
query is executed. A long-running EntityServer might accumulate large numbers of distinct
dynamic type definitions. The server could run out of memory if it saw millions of different
anonymous types in which case you'll have to recycle the server periodically if this becomes a
problem. It's not a great risk but we felt we should mention it.
SelectMany example
A dynamic implementation of the LINQ SelectMany operation also makes use of the
ProjectionSelector. The following contrived example shows how to use SelectMany to get the
OrderDetails associated with the first five Products in the database. It relies upon a peculiar
function, DoSelectMany, that gets an arbitrary set of related entities from the first five
instance of some kind of entity.
C#
public IEnumerable DoSelectMany(
EntityManager manager, Type entityType, string propertyName)
{
var selector = new ProjectionSelector(propertyName);

var rootQuery = EntityQuery.Create(entityType, manager);
var query = rootQuery
.Take(5) // reduce the result size for exposition.
.SelectMany(selector);
var results = query.Execute();
return results;
}

var orderDetails =
DoSelectMany(anEntityManager, typeof(Product), "OrderDetails")
.Cast<OrderDetail>() // convert IEnumerable to IEnumerable<OrderDetails>
.ToList();
VB
Public Function DoSelectMany(ByVal manager As EntityManager, _
ByVal entityType As Type, ByVal propertyName As string) As IEnumerable

var selector = New ProjectionSelector(propertyName)

Dim rootQuery = EntityQuery.Create(entityType, mManager)
Dim query = rootQuery
.Take(2) ' reduce the result size for exposition.
.SelectMany(selector)
Dim results = query.Execute()
Return results

End Function

Dim orderDetails =
DoSelectMany(anEntityManager, GetType(Product), "OrderDetails")
.Cast<OrderDetail>() ' convert IEnumerable to IEnumerable<OrderDetails>
.ToList()
GroupBy example

A dynamic implementation of the LINQ GroupBy operation also makes use of the
ProjectionSelector. In the following example, the SimpleGroupBy function queries for every
instance of a given type and groups the results by one of the properties of that type.
C#
public IEnumerable SimpleGroupBy(EntityManager manager,
Type entityType, string groupByProperty)
{
var groupBy = new ProjectionSelector(groupByProperty, alias);

var query = EntityQuery.Create(entityType, manager)
.GroupBy(groupBy);
var result = manager.ExecuteQuery(query);
return result;
}

// Static equivalent: anEntityManager.Products.GroupBy(_ => _.Category.CategoryName);
var result = SimpleGroupBy(anEntityManager,
typeof(Product), "Category.CategoryName");

var productGrps = result.Cast<IGrouping<String, Product>>().ToList();
VB
Public Function SimpleGroupBy(ByVal manager As EntityManager,
ByVal entityType As Type,ByVal groupByProperty As String) _
As IEnumerable

Dim groupBy = new ProjectionSelector(groupByProperty, alias)

Dim query = EntityQuery.Create(entityType, manager)
.GroupBy(groupBy)
Dim result = manager.ExecuteQuery(query)
Return result
End Function

' Static equivalent: anEntityManager.Products.GroupBy(Function(_) _.Category.CategoryName)
Dim result = SimpleGroupBy(anEntityManager,
GetType(Product), "Category.CategoryName")

Dim productGrps = result.Cast(Of IGrouping(Of String, Product))().ToList()

PropertyProjectionSelector is deprecated
The IdeaBlade.Linq.PropertyProjectionSelector is now obsolete, having been superseded by
the ProjectionSelector. It will be removed from the product at a future date.













Requery
Last modified on April 21, 2011 19:08
Contents
RefetchEntity/RefetchEntities methods
Fetch and Re-fetch of navigation properties
There are several ways of forcing the requery of previously cached data. This can important
when you want to insure that the local entity cache has the absolutely latest data.
One approach is to use one of the RefetchEntities overloads on the EntityManager:


RefetchEntity/RefetchEntities methods
C#
public void RefetchEntity(Object entity, MergeStrategy mergeStrategy);
public void RefetchEntities(IEnumerable entities, MergeStrategy mergeStrategy);
public void RefetchEntities(EntityKeyList entityKeys, MergeStrategy mergeStrategy);
public void RefetchEntities(EntityState entityState, MergeStrategy mergeStrategy);
VB
Public Sub RefetchEntity(ByVal entity As Object, ByVal mergeStrategy As MergeStrategy)
Public Sub RefetchEntities(ByVal entities As IEnumerable, ByVal mergeStrategy As MergeStrategy)
Public Sub RefetchEntities(ByVal entityKeys As EntityKeyList, ByVal mergeStrategy As
MergeStrategy)
Public Sub RefetchEntities(ByVal entityState As EntityState, ByVal mergeStrategy As
MergeStrategy)
There are also asynchronous versions of each of the above.
One warning about these methods; they are all designed to work with reasonably small
numbers of entities ( < 1000).
While they will work with larger numbers of entities; performance may be poor. 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.
The MergeStrategy determines how the refetched data will be merged into cache.
OverwriteChanges replaces the cached entities, overwriting our pending changes. We often
want to (a) keep pending changes but (b) refresh copies of unmodified entities. The
PreserveChanges strategies can help us achieve our purpose.
Strategy Description
OverwriteChanges
Overwrites the cached entity with incoming data and uses
the EntityState of the incoming entity
PreserveChanges
Replace unchanged entities but keep changed entities as
they are.
PreserveChangesUnlessOriginalObsolete
Preserves the persistent state of the cached entity if the
entity is current. Overwrites an entity if it is obsolete and
gives it the EntityState of the incoming entity.
PreserveChangesUpdateOriginal
Preserves the persistent state of the cached entity whether
it is current or not. Overwrites the Original version of the
entity if obsolete.
How is Current determined? DevForce uses the ConcurrencyProperties youve defined for
the Entity. If the values of the concurrency properties are the same between the original and
incoming entity, then the entity is considered current. If you havent defined a concurrency
property for the entity then DevForce has no way of determining currency correctly, so
assumes that the entity is current.
What do we mean by the Original version? Every entity can have up to three versions of
property values. All entities will have current values; modified entities will also have
original values, i.e., the property values before the entity was modified. Entities in edit
mode will also have proposed values, i.e., the values changed during the edit but not yet
committed.
Merge strategies are described in further detail later in this document.

Fetch and Re-fetch of navigation properties
You can also control how navigation properties are loaded, or force a re-load, using property
metadata for these properties called the NavigationEntityProperty. Remember that every
generated entity in the domain model has a nested PropertyMetadata class giving you access
to all EntityProperty definitions for that type. You can also obtain this information from the
EntityMetadataStore.
With the NavigationEntityProperty for a particular property in hand, you can then obtain the
EntityReference, which gives you low-level access to the property and its status. You obtain
the EntityReference from the NavigationProperty itself. For example,
C#
Customer aCustomer = _em1.Customers.First();
var navProp = Customer.PropertyMetadata.OrderSummaries;
var entityRef = navProp.GetEntityReference(aCustomer);
VB
Dim aCustomer As Customer = _em1.Customers.First()
Dim navProp = Customer.PropertyMetadata.OrderSummaries
Dim entityRef = navProp.GetEntityReference(aCustomer)
Once you have the EntityReference, a call to Load(MergeStrategy) will force a re-fetch of the
related entities, and use the specified MergeStrategy to merge the data into cache. The
MergeStrategy here functions exactly the same as when used with the EntityManager
RefetchEntities methods described above.
C#
Customer aCustomer = _em1.Customers.First();
Customer.PropertyMetadata.OrderSummaries.GetEntityReference(
aCustomer).Load(MergeStrategy.PreserveChangesUpdateOriginal);
VB
Dim aCustomer As Customer = _em1.Customers.First()
Customer.PropertyMetadata.OrderSummaries.GetEntityReference(aCustomer) _
.Load(MergeStrategy.PreserveChangesUpdateOriginal)
By default, all navigation properties are lazily loaded. To change this load strategy you can
do so easily using the ReferenceStrategy defined for every NavigationEntityProperty. For
example,
C#
var ers = new EntityReferenceStrategy(
EntityReferenceLoadStrategy.Load,
MergeStrategy.PreserveChanges);
var navProp = Customer.PropertyMetadata.OrderSummaries;
navProp.ReferenceStrategy = ers;
VB
Dim ers = New EntityReferenceStrategy(EntityReferenceLoadStrategy.Load, _
MergeStrategy.PreserveChanges)
Dim navProp = Customer.PropertyMetadata.OrderSummaries
navProp.ReferenceStrategy = ers
The EntityReferenceLoadStrategy is an enum which allows you to choose among "Lazy",
"DoNotLoad", and "Load" options. The default, Lazy indicates that the related data will be
loaded once when first accessed. Use "DoNotLoad" if the related data should not ever be
retrieved from the back end data store; and use "Load" to force a retrieval from the back end
data store upon every access.


Useful query extension methods
Last modified on April 21, 2011 19:08
Contents
The With() Extension Method
The FirstOrNullEntity() ExtensionMethod
The ToQuery () ExtensionMethod
DevForce provides several additional "query support" extension methods.. All of these
methods are defined as extensions to IEntityQuery.
The With() Extension Method
The With() extension method permits you to substitute a different QueryStrategy, a different
target EntityManager, or both, on any existing instance of an IEntityQuery. The original query
will be left unaltered.
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.
You can pass null arguments to With(). When a query has a null EntityManager assigned, it
uses the DefaultManager. When a query has a null QueryStrategy, it uses the
DefaultQueryStrategy of the assigned (or default) EntityManager. See the code below for
more detail on the possibilities.
C#
// Setup
DomainModelEntityManager em1 = null;
DomainModelEntityManager em2 = null;

IEntityQuery<Customer> query0 = em1.Customers
.Where(c => c.CompanyName.ToLower().StartsWith("a"))
.With(QueryStrategy.DataSourceOnly);

//Use With() to run the existing query against a different EntityManager:
List<Customer> customers = new List<Customer>(query0.With(em2));

//The next two examples use With() to run the query with a different QueryStrategy.
//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> query1 = query0.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> query2 = query0.With(QueryStrategy.DataSourceOnly);

//If you want to be certain you get a new query, use Clone()
//rather than With():
EntityQuery<Customer> query3 = (EntityQuery<Customer>)query0.Clone();
query3.QueryStrategy = QueryStrategy.DataSourceOnly;

//Change both the QueryStrategy and the EntityManager
IEntityQuery<Customer> query4 = query0.With(em2, QueryStrategy.CacheOnly);

//You can pass null arguments to With(). When a query has a null EntityManager,
//assigned, it uses the DefaultManager. When a query has a null QueryStrategy,
//it uses the DefaultQueryStrategy of the assigned (or default) EntityManager.
//Run the query against the default EntityManager, using its default QueryStrategy:
IEntityQuery<Customer> query5 = query0.With(null, null);

//When you pass a single null to With, you must cast it to the appropriate
//type so the compiler know's which single-parameter overload you mean to use:
//Run the query against the default EntityManager, using the base query's
//assigned QueryStrategy:
IEntityQuery<Customer> query6 = query0.With((DomainModelEntityManager)null);

//Run the query against the assigned EntityManager, using that EntityManager's
//default QueryStrategy:
IEntityQuery<Customer> query7 = query0.With((QueryStrategy)null);
VB
' Setup
Dim em1 As DomainModelEntityManager = Nothing
Dim em2 As DomainModelEntityManager = Nothing

Dim query0 As IEntityQuery(Of Customer) = em1.Customers.Where( _
Function(c) c.CompanyName.ToLower().StartsWith("a")). _
With(QueryStrategy.DataSourceOnly)

'Use With() to run the existing query against a different EntityManager:
Dim customers As New List(Of Customer)(query0.With(em2))

'The next two examples use With() to run the query
'with a different QueryStrategy.
'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 query1 As IEntityQuery(Of Customer) = _
query0.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 query2 As IEntityQuery(Of Customer) = _
query0.With(QueryStrategy.DataSourceOnly)

'If you want to be certain you get a new query, use Clone()
'rather than With():
Dim query3 As EntityQuery(Of Customer) = CType(query0.Clone(), _
EntityQuery(Of Customer))
query3.QueryStrategy = QueryStrategy.DataSourceOnly

'Change both the QueryStrategy and the EntityManager
Dim query4 As IEntityQuery(Of Customer) = query0.With(em2, _
QueryStrategy.CacheOnly)

'You can pass null arguments to With(). When a query has a null
'EntityManager assigned, it uses the DefaultManager. When a query has
'a null QueryStrategy, it uses the DefaultQueryStrategy of the
'assigned (or default) EntityManager.
'Run the query against the default EntityManager,
'using its default QueryStrategy:
Dim query5 As IEntityQuery(Of Customer) = _
query0.With(Nothing, Nothing)

'When you pass a single null to With, you must cast it to the appropriate
'type so the compiler know's which single-parameter overload you mean to use:
'Run the query against the default EntityManager, using the base query's
'assigned QueryStrategy:
Dim query6 As IEntityQuery(Of Customer) = _
query0.With(CType(Nothing, DomainModelEntityManager))

'Run the query against the assigned EntityManager, using that
'EntityManager's default QueryStrategy:
Dim query7 As IEntityQuery(Of Customer) = _
query0.With(CType(Nothing, QueryStrategy))
The FirstOrNullEntity() ExtensionMethod
LINQ to Entities provides First() and FirstOrDefault() extension methods on queries. First()
returns the first item in a collection meeting the query criteria; FirstOrDefault() returns that,
or if no items meet the criteria, the default value for the target type. For integer target types,
FirstOrDefault() returns a zero; for string types, it returns an empty string. For complex types
or other types that have no default, it returns a null.
DevForce adds a FirstOrNullEntity extension method that can be used when you are querying
for target types that inherit from IdeaBlade.EntityModel.Entity. If no entity meets the
specified criteria, FirstOrNullEntity() returns the DevForce NullEntity" for the target type.
The NullEntity is a non-saveable, immutable, syntactically correct instance of an entity
represents "nothing there" but will not trigger an exception.

The ToQuery () ExtensionMethod
Every IdeaBlade.EntityModel.Entity has a ToQuery() extension method that returns an
IEntityQuery<T> where T is an Entity type. This IEntityQuery<T> specifies the Entity on
which it was based using its EntityAspect.EntityKey, and can be extended to perform various
useful operations. Consider, for example, the following statements:
C#
Customer aCustomer = _em1.Customers.FirstOrNullEntity();
var query = aCustomer.ToQuery<Customer>()
.Include(Customer.PathFor(c => c.Orders));
query.With(QueryStrategy.DataSourceOnly).ToList();
VB
Dim aCustomer As Customer = _em1.Customers.FirstOrNullEntity()
Dim query = aCustomer.ToQuery().Include(Customer.PathFor(Function(c) c.Orders))
query.With(QueryStrategy.DataSourceOnly).ToList()
Here, from a Customer entity, we have created a query that will retrieve that same Customer.
We have then extended with a call to Include() it to create a span query that will also retrieve
all of that Customers associated Orders. We do not otherwise have so convenient a way to
accomplish this goal.
The ToQuery() extension method is also provided on any IEnumerable<T> collection, when
T is an Entity. Thus you can turn an arbitrary list of Customers into a query that will return
the same set of Customers. The Where() clause on the resultant query will specify a series of
ORd key values. For example, consider the following statements:
C#
List<Customer> customers = _em1.Customers
.Where(c => c.CompanyName.ToLower().StartsWith("a")).ToList();
var query2 = customers.ToQuery<Customer>();
VB
Dim customers As List(Of Customer) = _em1.Customers _
.Where(Function(c) c.CompanyName.ToLower().StartsWith("a")).ToList()
Dim query2 = customers.ToQuery()
Placing query2 in a watch window reports its value as the following:
{value(IdeaBlade.EntityModel.EntityQueryProxy`1[DomainModel.Customer]).Where(t =>
((((t.CustomerID = 785efa04-cbf2-4dd7-a7de-083ee17b6ad2) || (t.CustomerID = b61cf396-
206f-41a6-9766-168b5cbb8edd)) || (t.CustomerID = f214f516-d55d-4f98-a56d-
7ed65fd79520)) || (t.CustomerID = 256d4372-baa7-4937-9d87-d9a4e06146f8)))}
The first query evidently placed four Customers in the customers list; the query returned by
ToQuery() specifies those four by their (GUID) key values.
Add a named query
Write a named query method on the server when you want explicit control over how the
server interprets a LINQ query received from the client.


Named queries make it easy to dictate the server-side implementation of a query. You can
write several named queries for a particular entity type which means you can offer clients a
menu of query alternatives that each express a distinctive intent.
A named query is a convenient way to consolidate in a single method the logic to:
authorize the query
modify the query, perhaps by adding filters or limiting the amount of data returned
add Include clauses that package related entities in the query result
Named queries are methods that return an IQueryable or an IEnumerable of an entity type.
The type can be any serializable class produced by almost any means imaginable. Most
named queries will involve Entity Framework entity types produced by an Entity Framework
query.
There are two basic kinds of named query: the default named query and specialized named
queries.
Named queries were introduced as a beta feature in DevForce version 6.1.0.0
The default named query
The default named query is a named query that represents all entities of a particular type in
the database. The signature of the default named query for the Customer entity type might be
as follows:
C# public IQueryable<Customer> GetCustomers();
VB public IQueryable(Of Customer) GetCustomers()
Various GetCustomers implementations are considered in the "default named query" topic.
For the moment it's worth noting that
the method returns an IQueryable (or IEnumerable) of a specific type
there are no parameters
the method name consists of a "Get" prefix followed by an EntitySet name, usually the plural
form of the entity type name; you'll learn how to name a query method elsewhere.
When the EntityServer receives a Customer client query that corresponds to this named query,
it builds a new query by copying the client query LINQ clauses and adding them to the output
of the named query method.
All named queries are composable in this way. For example, DevForce translates a client
query for Customers beginning with the letter 'B' such as this one:
C# myEntityManager.Customers.Where(c => c.StartsWith("B");
VB myEntityManager.Customers.Where(Function(c) c.StartsWith("B")
into something like:
C# GetCustomers().Where(c => c.StartsWith("B");
VB GetCustomers().Where(Function(c) c.StartsWith("B")
The EntityServer
Default named queries are optional
You do not have to write a default named query method. When the DevForce EntityServer
receives a client query and there is no default named query method on the server, DevForce
processes it directly using its own default get-all-entities query as the root.
If you decide to write a default named query, you can write only one per entity type.
Specialized named queries
The developer may wish to write one or more specialized named query methods for a
particular entity type. Each method is associated with a particular business purpose and,
accordingly, returns a different set of entities. For example, you might have one specialized
named query for Gold Customers and another specialized named query returning the
current users Western Region Customers.
Specialized named query methods can take parameters, unlike the default named query which
must be parameterless.
The EntityServer must be able to find the specialized named query method if the client query
asks for it.
Write a class for the named query methods
Named queries are instance methods of a class. DevForce can find them if the class resides in
a discoverable assembly.
There isnt much special about that class and you can have as many such classes as you like.
There are only a few requirements.
1. it must be public
2. it must have a default constructor (or no constructor)
3. it must be adorned with the EnableClientAccess attribute.
4. it must reside in an assembly that the DevForce EntityServer will discover.
Please keep your named query provider classes stateless if possible. If it must have state, give
great care to ensuring safe concurrent access to that state.
Please avoid putting anything in this class other than what is strictly necessary to achieve its
purpose. The named query provider class is a poor choice for a grab-bag of server-side
features.
Here is an example of a provider class.
C#

[EnableClientAccess]
public class NamedQueryServiceProvider {
public IQueryable<Customer> GetCustomers() {...}
}
VB
<EnableClientAccess>
Public Class NamedQueryServiceProvider
Public Function GetCustomers() As IQueryable(Of Customer)
...}
End Function
You must put this NamedQueryServiceProvider class in an assembly deployed on the server.
The domain model project would do; the domain model assembly is always discoverable and
deployed to the server. If you do not want the named query methods exposed on the client,
add it to a separate, full .NET class library project that you only deploy to the server.
Assembly discovery is discussed here.
Named query security
We trust you are authenticating clients before you accept their queries. Even so, you may be
uncomfortable simply executing every query a client sends you, even if the client has been
authenticated. You may prefer to inspect, modify, and possibly reject a query.
The easiest approach is to add query security attributes to the method definitions. The
DevForce EntityServerQueryInterceptor is affords the most complete and custom control
over the query and its interpretation. You can inherit from our base version of that class and
override one or more of its virtual methods. The DevForce EntityServer calls these methods as
it processes the query. Your overrides can terminate the query, replace or modify the query, or
even alter the query results.
Such an interceptor remains the most powerful query management mechanism in DevForce.
All queries named and unnamed pass through the interceptor. Anything you can do in a
named query you can do in the interceptor. Many developers will combine named queries and
query interception for a balance of convenience and power.
Learn more
Other subordinate topic pages explain in greater detail how to write named queries and use
them appropriately.


Add the default named query
The default named query is a server-side query method that represents the entire EntitySet
for a given entity type. In this topic we discuss what a default named query is and how to
write one.


The default named query is a server-side query method that represents the entire EntitySet for
a given entity type. For example, the EntitySet for the Customer entity type is called
Customers. When a client submits a query that is rooted in the Customers EntitySet and
youve written a named query method for that EntitySet, such as GetCustomers, then that
method is the default named query.
Conceptually the default named query means return to the client every instance of this type.
You write this method on the server. Whether it in fact returns every instance of the type is up
to you.
The following discussion begins with a client query for Customers when there is no named
query. It identifies the root query to which you add filters, ordering, grouping, and selection.
Then it shows two examples of a default named query that DevForce EntityServer substitutes
for the root query when processing a query from the client.
A separate topic explains how to write a specialized named queries that can address a
narrower business purpose.
A simple client query
Here is a query that you might write on the client to retrieve all customers in the database.
C# query = myEntityManager.Customers; // uses the generated query property
VB query = myEntityManager.Customers ' uses the generated query property
Customers is a factory property that returns an EntityQuery for Customer entities. The
DevForce code generator added this property to the models custom EntityManager for your
convenience. When you examine the generated code file, youll see that it was implemented
as follows:
C# query = new EntityQuery<Customer>("Customers", myEntityManager);
VB query = New EntityQuery(Of Customer)("Customers", myEntityManager)

Locate the EntityQueries region of the generated entity class file.
The string, Customers, is the name of the EntitySet associated with the Customer entity
type. DevForce interprets this to mean the unrestricted set of all customers.
The query is also associated with a particular EntityManager, the one in the myEntityManager
variable. That means the query can be executed directly by writing something like this
C# query.ExecuteAsync(queryCallBack); // get the results in the callback
VB query.ExecuteAsync(queryCallBack) ' get the results in the callback
We dont have to specify the EntityManager when we create the query. We might want to re-
use the query with different EntityManager instances in which case we can write.
C#
query = new EntityQuery<Customer>("Customers");
em1.ExecuteQueryAsync(query, queryCallback);
em2.ExecuteQueryAsync(query, queryCallback);
VB
query = New EntityQuery(Of Customer)("Customers")
em1.ExecuteQueryAsync(query, queryCallback)
em2.ExecuteQueryAsync(query, queryCallback)
Query Root
The client query examples weve seen so far return all customers in the database. Of course
you can restrict the query further by adding Where clauses such as one that returns only
customers beginning with the letter B.
C#
query-B-Customers = new EntityQuery<Customer>("Customers")
.Where(c => c.StartsWith("B");
myEntityManager.ExecuteQueryAsync(query-B-Customers, queryCallback);
VB
query-B-Customers = New EntityQuery(Of Customer)("Customers").Where(Function(c)
c.StartsWith("B")
myEntityManager.ExecuteQueryAsync(query-B-Customers, queryCallback)
Both the original query and this filtered query begin with the same root, the
EntityQuery("Customers"). This is the root of the query no matter what LINQ clauses are
added, no matter what types are ultimately returned.
Customers is the name of the EntitySet that includes all Customer entities in the database. It
defines the default query.

Keep your eye on the root and the EntitySet name. If you create a specialized named query (as
described elsewhere), you will create a different root that uses a different EntitySet name.
Add a do-nothing named query
Now lets write a default named query method in a named query provider class.
C#
public IQueryable<Customer> GetCustomers() {
return new EntityQuery<Customer>();
VB
Public Function GetCustomers() As IQueryable(Of Customer)
Return New EntityQuery(Of Customer)()
End Function
}
Named queries are methods that return an IQueryable or an IEnumerable of an entity type.
GetCustomers returns an IQueryable of Customer.
The definition of this query method should seem familiar. The returned value is almost
exactly the same as the EntityQuery we wrote on the client. Its only missing the EntitySet
string (Customers). Thats OK because DevForce infers the Customers entity set name
automatically.
It also lacks an EntityManager. That is to be expected on the server; the query will be used by
a different EntityManager instance every time.
DevForce can tell that this is a query method for the Customer type because it has the right
signature. It has no parameters and returns an IQueryable of Customer. DevForce also
determines that this is the default named query: the named query to use when the client
sends a query specifying the Customers EntitySet.
The EntityServer found this method by applying the DevForce query naming conventions
during its search. It stripped off the Get from the method name, leaving the word
Customers which matches the name of the Customer types EntitySet. You can use the
Query
Merging the named query with the original client query
Once DevForce finds the named query that matches the clients query, it merges the two
queries by copying the LINQ clauses of the client query to the output of the named query
method. You can imagine DevForce doing something like the following with query-B-
Customers:
C#
// query-B-Customers = new EntityQuery<Customer>().Where(c => c.StartsWith("B");
mergedQuery = GetCustomers().Where(c => c.StartsWith("B");
VB
' query-B-Customers = new EntityQuery<Customer>().Where(c => c.StartsWith("B");
mergedQuery = GetCustomers().Where(Function(c) c.StartsWith("B")
Then the EntityServer forwards the mergedQuery to the DevForce
EntityServerQueryInterceptor or to your custom EntityServerQueryInterceptor
Add a do-something named query
The GetCustomers method we just wrote does exactly what DevForce would do anyway.
Theres no point in writing a default named query unless it adds value.
You do not have to write a default named query.
But we can write a GetCustomers method that adds value such as this one:
C#
[RequiresRoles("admin")]
public IQueryable<Customer> GetCustomers() {
return new EntityQuery<Customer>().Include("Orders");
}
VB
<RequiresRoles("admin")>
Public Function GetCustomers() As IQueryable(Of Customer)
Return New EntityQuery(Of Customer)().Include("Orders")
End Function
Now only administrators can issue a query for Customers, thanks to the RequiresRoles
attribute . The query also automatically includes the Order entities related to the Customers
returned by the query.
The result returned to the client will be further restricted to Customers whose names begin
with B because that criterion was copied over from the client's query-B-Customers query.

Lets try a different implementation:
C#
public IQueryable<Customer> GetCustomers() {
var user = System.Threading.Thread.CurrentPrincipal as User;
EnsureValidUser(user);
// only show the users own Customers
return new EntityQuery<Customer>()
.Where(c => c.UserID = user.ID);
}
VB
Public Function GetCustomers() As IQueryable(Of Customer)
Dim user = TryCast(System.Threading.Thread.CurrentPrincipal, User)
EnsureValidUser(user)
' only show the users own Customers
Return New EntityQuery(Of Customer)().Where(Function(c) c.UserID = user.ID)
End Function
In this one, the named query extracts the user from the server IPrincipal and limits the query
to Customers that belong to the client user only. The EnsureValidUser method (not shown)
throws a useful exception if the IPrincipal is not a proper User object.
After merging with the client query-B-Customers, the query results contain only those
Customers whose names begin with B and
The client query does not change
You can add, modify, or delete the default named query without changing your client query.
Client query syntax remains the same and the query is used the same way, with or without a
default named query on the server. The presence, absence, or nature of the default named
query is structurally and functionally transparent to the client.

Of course the default named query itself can change what entities are returned from the data
store. Thats why you wrote it. The named query may even reject the client query and throw
an exception. These behaviors are up to you.
The default named query applies to the cache
A client query that is rooted in the default named query can be applied to the local entity
cache.

If the querys QueryStrategy is Optimized or DataSourceThenCache or CacheOnly, the query
will include cached entities. If the EntityManager is disconnected, the query applies to the
cache. The EntityManager can also remember the query in its query cache, potentially
avoiding a redundant trip to the server when the query is executed a second time.
This is not true for specialized named queries described elsewhere. They are always executed
as DataSourceOnly queries and are never remembered in the query cache. They always fail if
executed offline. The reason for this difference is explained in the topic on specialized named
queries.
Only one default named query
You dont have to write a default named query. If you do, there can be only one named query
method per entity type. There can be only one named query method associated with an entity
types EntitySet and that one method must not take parameters.
Another topic covers parameterized named queries. The default named query may not have
parameters.





Add specialized named query
You can write a specialized named query to reflect a particular business intent such as
retrieving gold customers.


A specialized named query typically supplements the default named query. It differs from the
default named query in that it tends to restrict the range of queryable entities to a specific
subset that represents an application domain concept. The default named query for Customer
represents all customers. A specialized named query called GetGoldCustomers likely returns
a highly-prized subset of those customers.
You can write as many specialized named queries as you need.
An example
Suppose your business makes special offers for gold customers. While you could specify
what makes a customer golden in the client query, for some reason you prefer to make that
determination on the server. Lets write that specialized named query in a named query
provider class:
C#
// Customers who spent more than 10,000 this year
public IQueryable<Customer> GetGoldCustomers() {
var thisYear = new DateTime(DateTime.Today.Year, 1, 1);
return new EntityQuery<Customer>()
.Where(c => 10000 < c.Orders
.Where(o => o.OrderDate >= thisYear)
.Sum(o => o.OrderDetails.Sum(od => od.Quantity * od.UnitPrice)));
}
VB
' Customers who spent more than 10,000 this year
Public Function GetGoldCustomers() As IQueryable(Of Customer)
Dim thisYear = New Date(Date.Today.Year, 1, 1)
Return New EntityQuery(Of Customer)().Where(Function(c) 10000 < c.Orders _
.Where(Function(o) o.OrderDate >= thisYear).Sum(Function(o) o.OrderDetails _
.Sum(Function(od) od.Quantity * od.UnitPrice)))
End Function
All named query methods return an IQueryable or an IEnumerable of an entity type.
GetGoldCustomers returns an IQueryable of Customer.
You could invoke this query with the following client statements:
C#
query-B-GoldCustomers = new EntityQuery<Customer>("GoldCustomers")
.Where(c => c.StartsWith("B"));

myEntityManager.ExecuteQueryAsync(query-B-GoldCustomers, queryCallback);
VB
query-B-GoldCustomers = New EntityQuery(Of Customer)("GoldCustomers") _
.Where(Function(c) c.StartsWith("B"))

myEntityManager.ExecuteQueryAsync(query-B-GoldCustomers, queryCallback)
The named querys EntitySet name
Notice that the EntitySet name provided to the EntityQuery constructor is GoldCustomers.
The Customer entity type's true EntitySet name is Customers, not GoldCustomers.
"Customers" refers to all Customer entities in the data source. Only some of those customers
are "gold customers." You can think of GoldCustomers as a subset of the "Customers"
EntitySet.
As a practical matter, DevForce uses the GoldCustomers name to find the corresponding
query method on the server. The EntityServer applies the DevForce query naming
conventions to locate the query method, stripping the "Get" prefix from the
GetGoldCustomers method name and matching the remaining GoldCustomers text to the
EntitySet name in the client EntityQuery.
You can use the Query attribute to identify a query method that does not conform to the
conventions as explained in the query naming conventions topic.
If the client query asks for a specialized named query, the EntityServer must be able to find
the corresponding query method on the server; it will throw an exception if it cant find the
method.
Merging the named query with the original client query
DevForce merges the client query with the named query by copying the LINQ clauses of the
client query LINQ to the output of the named query method. The re-composition works
something like this:
C# mergedQuery = GetGoldCustomers().Where(c => c.StartsWith("B"));
VB mergedQuery = GetGoldCustomers().Where(Function(c) c.StartsWith("B"))
The re-composed query returns B customers who spent $10,000 during the current calendar
year.
Create a property for the named query
Notice the hard-coded the "GoldCustomers" string in the client query. That is a risky practice.
It's a better idea to hide that magic string inside a dedicated, query-producing property or
method.
The DevForce code generator does something similar when it creates EntityQuery factory
properties for the entity model's custom EntityManager. The Customers property, shown here,
is typical:
C#
using IbEm = IdeaBlade.EntityModel;
...
public partial class NorthwindManager : IbEm.EntityManager {
...
public IbEm.EntityQuery<Customer> Customers {
get { return new IbEm.EntityQuery<Customer>("Customers", this); }
}
...
}
VB
Imports IbEm = IdeaBlade.EntityModel
...
Partial Public Class NorthwindManager
...
Inherits IbEm.EntityManager
Public ReadOnly Property Customers() As IbEm.EntityQuery(Of Customer)
Get
Return New IbEm.EntityQuery(Of Customer)("Customers", Me)
End Get
...
End Property
End Class
Notice that DevForce generated NorthwindManager as a partial class. You can extend it with
EntityQuery factory properties for your specialized named queries as illustrated by this
GoldCustomers property:
C#
public partial class NorthwindManager {
...
public IbEm.EntityQuery<Customer> GoldCustomers {
get { return new IbEm.EntityQuery<Customer>("GoldCustomers", this); }
}
...
}
VB
Partial Public Class NorthwindManager
...
Public ReadOnly Property GoldCustomers() As IbEm.EntityQuery(Of Customer)
Get
Return New IbEm.EntityQuery(Of Customer)("GoldCustomers", Me)
End Get
End Property
...
End Class

The DevForce code generator will write this property for you in a future release.
Now you can write a GoldCustomers query in your application code in the same manner as
you would write a regular Customer query:
C#
customersQuery = myEntityManager.Customers.Where(...);
...
goldCustomersQuery = myEntityManager.GoldCustomers.Where(...);
VB
customersQuery = myEntityManager.Customers.Where(...)
...
goldCustomersQuery = myEntityManager.GoldCustomers.Where(...)

Specialized named queries in OData
You can use OData to invoke specialized named queries as long as you create a custom
EntityManager factory property for that query as just explained.
You don't have to do anything to support OData queries that depend on the default named
query. DevForce generated their factory properties automatically.
Specialized named queries are DataSourceOnly
A query rooted in a specialized named query must be executed using the DataSourceOnly
QueryStrategy.
DevForce converts the default Optimized QueryStrategy to DataSourceOnly automatically.
The query is never remembered in the query cache, it ignores entities in cache, and it always
fails if executed offline.
A query that is rooted in the default named query, on the other hand, can be remembered in
the query cache, can be applied to the cache, and can execute even when the application is
offline. Why the difference?
The default named query is associated with the entity types EntitySet. That EntitySet
represents the unrestricted view of all instances of the entity type. DevForce adopts this
interpretation whether or not youve written a default named query, even if your
implementation of the default named query in fact restricts query results to a handful of the
possible entities.

Because DevForce assumes that the default root query embraces all entities of the type, it acts
as if every entity in cache is fair game.
Please keep these semantics in mind when you write a default named query. The client application
should be able to assume that a query for all Customers returns every Customer that the current user
would ever be allowed to see.
DevForce gives the opposite interpretation to a specialized named query. Presumably you
wrote a specialized named query for two reasons: (1) to limit the range of possible query
results to a subset of the entity domain and (2) to hide that limiting logic from the client.
If you had wanted the client to know how it worked, you would have written the query as a
client query. Instead, you chose to keep the logic a secret from the client by writing a
specialized named query on the server. From the client perspective, a specialized named query
is a black box.
DevForce cannot confidently reproduce the server-side behavior of the query on the client and
does not try. DevForce concludes that the query must be executed on the server and only on
the server. An attempt to force an EntityManager to evaluate the query on the client must fail
with an exception.
Specialized named queries can take parameters
You can pass parameters to a specialized named query. This topic explains how and why.
Parameterized named query
You can define a specialized named query that accepts parameters to constrain the
behavior of the named query.


Here is a parameterized named query that retrieves Customers whose names begin with a
prefix string.
C#
public IQueryable<Customer> GetCustomersStartingWith(string prefix)
{
return new EntityQuery<Customer>().Where(c => c.Name.StartsWith(prefix));
}
VB
Public Function GetCustomersStartingWith(ByVal prefix As String) As IQueryable(Of Customer)
Return New EntityQuery(Of Customer)().Where(Function(c) c.Name.StartsWith(prefix))
End Function
The client provides the prefix by adding a parameter to the client query:
C#
var query = IbEm.EntityQuery<Customer>("CustomersStartingWith", myEntityManager);
query.Parameters.Add(new EntityQueryParameter(prefix));
VB
Dim query = IbEm.EntityQuery(Of Customer)("CustomersStartingWith", myEntityManager)
query.Parameters.Add(New EntityQueryParameter(prefix))
Notice the EntitySet name, CustomersStartingWith, that corresponds to the specialized
named query on the server.
These two lines make sense after close study but they are not easily grasped at a glance. Its a
good practice to wrap them in a method that you add to the models custom EntityManager,
as illustrated here:
C#
public partial class NorthwindManager {
...
public IbEm.EntityQuery<Customer> GetCustomersStartingWith(string prefix)
{
var query = IbEm.EntityQuery<Customer>("CustomersStartingWith", this);
query.Parameters.Add(new EntityQueryParameter(prefix));
return query;
}
...
}
VB
Partial Public Class NorthwindManager
Public Function GetCustomersStartingWith(ByVal prefix As String) _
As IbEm.EntityQuery(Of Customer)
Dim query = IbEm.EntityQuery(Of Customer)("CustomersStartingWith", Me)
query.Parameters.Add(New EntityQueryParameter(prefix))
Return query
End Function
End Class
The DevForce code generator will write this method for you in a future release.

Now you can write a simple GetCustomersStartingWith query in your application code:
C# query = myEntityManager.CustomersStartingWith("B").Where(...);
VB query = myEntityManager.CustomersStartingWith("B").Where(...)
Multiple parameters, multiple overloads
A parameterized named query can have as many parameters as you require. Be sure that you
add parameters to the client query that are of the same type and in the same order as the
parameters of the named query method on the server.
You can specify the name of the parameter in the constructor of the EntityQueryParameter.
That eases analysis of the query within your custom EntityServerQueryInterceptor but it
doesnt influence how DevForce matches the client query to the named query on the server.
The .NET reflection API doesn't reveal method parameter names.
If you write two specialized named queries with the same method name, DevForce attempts to
pick the best-fit overload by matching the parameters in the client query with the parameters
of the candidate query methods.
When to use parameterized named queries
You may not need parameterized queries. It is usually easier and clearer to write a client-side
query that incorporates the would-be-parameter information in the LINQ clauses.
Why not get the "B" customers with this garden variety Customer query?
C# query = myEntityManager.Customers.Where(c=>c.Name.StartsWith("B") && ...);
VB query = myEntityManager.Customers.Where(Function(c) c.Name.StartsWith("B") AndAlso ...)
When the EntityServer receives this query, it copies the LINQ clauses from the original client
query to the output of the named query method as if you had written:
C# GetCustomers().Where(c => c.StartsWith("B");
VB GetCustomers().Where(Function(c) c.StartsWith("B")
This is efficient and effective when the named query method (GetCustomers in this case)
returns an IQueryable.
However, this approach can be extremely inefficient if the named query method returns an
IEnumerable instead of an IQueryable. Such a method might cause the server to fetch an
enormous number of entities from the database when, in fact, the client only wants a small
subset of those entities.

True, the LINQ clauses from the client query reduce the transmitted results to just the entities
the client requested. But this reduction occurs in server memory after the full set of entities
had been retrieved and the damage done.
Its usually best to write named queries that return IQueryable when you can. Sometimes you
cant. For example, you might have to implement the named query with Entity SQL (ESQL);
ESQL queries return IEnumerable.
Here is a parameterized named query that uses DevForce ESQL to get Customers whose
names begin with a prefix string:
C#
public IEnumerable<Customer> GetCustomersStartingWith(string prefix) {
var param = new QueryParameter("prefix", prefix);
var paramEsql = new ParameterizedEsql(
"SELECT VALUE c FROM Customers AS c WHERE c.NAME LIKE '@prefix%'", param);
var query = new PassthruEsqlQuery(typeof(Customer), paramEsql);
var results = query.Execute().Cast<Customer>();
return results;
}
VB
Public Function GetCustomersStartingWith(ByVal prefix As String) As IEnumerable(Of Customer)
Dim param = New QueryParameter("prefix", prefix)
Dim paramEsql = New ParameterizedEsql( _
"SELECT VALUE c FROM Customers AS c WHERE c.NAME LIKE '@prefix%'", param)
Dim query = New PassthruEsqlQuery(GetType(Customer), paramEsql)
Dim results = query.Execute().Cast(Of Customer)()
Return results
End Function
The client invokes this server-side parameterized query method using the same custom client-
side myEntityManager.GetCustomersStartingWith method we showed earlier:
C# query = myEntityManager.CustomersStartingWith("B").Where(...);
VB query = myEntityManager.CustomersStartingWith("B").Where(...)
The prefix parameter contributes to the ESQL query, reducing the number of Customer
Limitations
The default named query method cannot take parameters.
All parameterized named queries are specialized which means they are not remembered in
the query cache, are not applied to entities in cache, and will fail if executed while the
application is offline.
You cannot refer to a parameterized named query in an OData query.

Intercept a named query
All queries processed on the EntityServer including named queries pass through the
DevForce EntityServerQueryInterceptor or a custom EntityServerQueryInterceptor if you
wrote one. This topic describes how you can distinguish between named and unnamed queries
and intervene as you deem appropriate.


Your custom EntityServerQueryInterceptor can inspect properties of the EntityQuery to
determine where it came from and how it was composed. You can alter the query or even
change the query results before they are transmitted to the client.
Everything your interceptor could do to an unnamed client query it can do to the re-composed
query derived from a named query.
Cast the query as an EntityQuery
The EntityServerQueryInterceptor handles every query that implements IEntityQuery. A
typical first step is to determine what kind of query you are intercepting and respond
accordingly. A named query is necessarily an EntityQuery so you might start by casting to
EntityQuery as in the following example:
C#
public class MyEntityServerQueryInterceptor :
EntityServerQueryInterceptor
{
protected override bool FilterQuery() // called before processing the query
{
EvaluateEntityQuery();
return base.FilterQuery();
}

private void EvaluateEntityQuery()
{
var entityQuery = this.Query as EntityQuery;
if (null == entityQuery) return; // not an EntityQuery;
...
}
}
VB
Public Class MyEntityServerQueryInterceptor
Inherits EntityServerQueryInterceptor
Protected Overrides Function FilterQuery() As Boolean
' called before processing the query
EvaluateEntityQuery()
Return MyBase.FilterQuery()
End Function

Private Sub EvaluateEntityQuery()
Dim entityQuery = TryCast(Me.Query, EntityQuery)
If Nothing Is entityQuery Then ' not an EntityQuery;
Return
End If
...
End Sub
End Class
Check IsNamedQuery
The EntityQuery.IsNamedQuery property returns true if
the intercepted query was constructed from a named query.
the property is called on the server inside the EntityServerQueryInterceptor.
Otherwise EntityQuery.IsNamedQuery returns false and the other named-query-related
properties discussed here return null or false.
The EntityServerQueryInterceptor.FilterQuery virtual method is a good place to check for
named queries. If you require that all client queries be routed through named queries, you can
throw a custom exception when IsNamedQuery is false.
You could add the following to the EvaluateEntityQuery method from the previous example:
C# if (!entityQuery.IsNamedQuery) throw new NamedQueryException("Not a named query");
VB
If Not entityQuery.IsNamedQuery Then
Throw New NamedQueryException("Not a named query")
End If
The EntityServer terminates query processing and transmits the exception to the client.
A more flexible approach is to maintain a whitelist of entity types which do not require named
query methods. Throw the exception if the unnamed query isn't on the list:
C#
Type rootQueryType = entityQuery.QueryableType; // the entity type being queried
if (!(entityQuery.IsNamedQuery || UnnamedQueryWhitelist.Contains(rootQueryType))
throw new NamedQueryException("Not a named query");
}
VB
Dim rootQueryType As Type = entityQuery.QueryableType ' the entity type being queried
If Not(entityQuery.IsNamedQuery OrElse UnnamedQueryWhitelist.Contains(rootQueryType))
Then
throw New NamedQueryException("Not a named query")
End If
Properties of named queries
The following properties of the EntityQuery class return meaningful values on the server
when the intercepted query is a named query.
Property Description
OriginalClientQuery
The original query from the client exactly as it was received by the
server.
NamedQuery
The query output of the named query method. This is the root of
the query that the interceptor is evaluating.
NamedQueryMethod The reflection MethodInfo of the named query method.
NamedQueryResultIsEnumerable
Is true if the query method returns an IEnumerable; false if
IQueryable
See the topics dedicated to the EntityServerQueryInterceptor to learn about other ways to
intervene in query processing.
IEnumerable named query
A named query method returns either an I Queryableor an I Enumerableof an entity type.
This topic explains the implications of each choice.


The query that the DevForce EntityServer actually processes is the result of copying LINQ
clauses from the original client query and attaching them to the output of the named query
method. The output of the named query can be either an IQueryable or an IEnumerable of an
entity type. The difference is important.
What's the difference?
An I Queryableis an expression tree. The LINQ clauses from the original client query are
added to that expression tree, effectively redefining the query before it is executed
An I Enumerable, on the other hand, is a delegate, an impenetrable function. The LINQ
clauses added from the original client query take effect after the delegate has been executed.
Those clauses filter, sort, group, and page the in-memory entities produced by the delegate.
Performance implications
The difference can profoundly affect performance on the server and on the database. An
example may help clarify. Imagine
there are 10,000 customers in the database.
only 100 of them have names that begin with the letter B.
the client send a query that retrieves only the B customers.
youve written a default named query called GetCustomers().
The EntityServer will merge the client and named queries yielding something akin to this:
C# GetCustomers().Where(c => c.StartsWith("B"))
VB GetCustomers().Where(Function(c) c.StartsWith("B"))
Suppose the GetCustomers named query method returns IQueryable
C#
public IQueryable<Customer> GetCustomers() {
return new EntityQuery<Customer>();
}
VB

Public Function GetCustomers() As IQueryable(Of Customer)
Return New EntityQuery(Of Customer)()
End Function

When the re-composed query executes, it will retrieve 100 Customer entities from the database.
Suppose instead that the GetCustomers named query method returns IEnumerable as in this
contrived example:
C#
public IEnumerable<Customer> GetCustomers() {
return new EntityQuery<Customer>().ToList();
}
VB
Public Function GetCustomers() As IEnumerable(Of Customer)
Return New EntityQuery(Of Customer)().ToList()
End Function
The merged query has not changed. It still has a Where clause that filters for the Bs. But
this time, the server fetches all 10,000 customers from the database thanks to the ToList()
method. Only after the 10,000 customers arrive on the server will the Where clause kick in
and filter the results down to the 100 customers the client actually wanted.
The client receives only 100 customers with either GetCustomers implementation. It neither
knows nor cares how the server did its job. But with the IEnumerable version of
GetCustomers, the EntityServer
When to use IEnumerable
Clearly IEnumerable is a poor choice for Customer queries. It might be a good choice for
small, stable entity lists.
Imagine that your business is very popular. Many clients are constantly online, badgering the
server repeatedly with requests for your product catalog. Your catalog has only 100 highly
sought after items that dont change very often perhaps a few times per day. Youd like to
avoid the pressure of unnecessary trips to the database by caching the product list on the
EntityServer. You can do that with a named Product query.
C#
public IEnumerable<Product> GetProducts() {
return ThreadSafeProductCatalog.GetLatestList(); // periodically self-updates
}
VB
Public Function GetProducts() As IEnumerable(Of Product)
Return ThreadSafeProductCatalog.GetLatestList() ' periodically self-updates
End Function
Consider this different scenario. You have a specialized named query method that cant be
implemented as an IQueryable. For some reason you had to implement it with Entity SQL
(ESQL); ESQL queries return IEnumerable.
Here is a contrived DevForce ESQL version of GetCustomersStartingWithB
C#
public IEnumerable<Customer> GetCustomersStartingWithB() {
var query = new PassthruEsqlQuery(
typeof(Customer),
"SELECT VALUE c FROM Customers AS c WHERE c.NAME LIKE 'B%'");
var results = query.Execute().Cast<Customer>();
return results;
}
VB
Public Function GetCustomersStartingWithB() As IEnumerable(Of Customer)
Dim query = New PassthruEsqlQuery(GetType(Customer), _
"SELECT VALUE c FROM Customers AS c WHERE c.NAME LIKE 'B%'")
Dim results = query.Execute().Cast(Of Customer)()
Return results
End Function
See the parameterized named queries topic for an example of a parameterized ESQL named
query.
Query method naming conventions
When the EntityServer receives a client query request, it looks on the server for a
corresponding query method such as a named query or POCO query method. It recognizes a
server-side query method by its signature and name. This topic explains the DevForce query
method naming convention and how to use the QueryAttribute when you can't follow the
convention.


The client query
At the root of a client EntityQuery is the name of the EntitySet that identifies the domain of
entities to query. Here is an example client query for Customers.
C# var query = new EntityQuery<Customer>("Customers", anEntityManager).Where(...);
VB Dim query = New EntityQuery(Of Customer)("Customers", anEntityManager).Where(...)
"Customers" is the name of EntitySet for the Customer entity type.
The more familiar anEntityManager.Customers() property returns an EntityQuery that is defined in
precisely this way.
If your query depends upon a specialized named query, the EntitySet name will be something
else. It might be "GoldCustomers" if you've defined a named query that implements that
concept.
Finding the server-side query method
When the EntityServer receives that client query, it looks for a method on the server that
corresponds to the EntityQuery's EntitySet name.
If it can't find a corresponding query method on the server there could be trouble. In most
cases the EntityServer throws an exception reporting its inability to find a method to go with
the requested EntitySet name.
There is one exception. The EntityServer can muddle through if the query's EntitySet name
matches the EntitySet name of an Entity Framework entity type. Because "Customers" is the
name of the EntitySet for the Customer EF type, DevForce doesn't have to find a matching
query method on the server. It will try to find a server-side method ... but it can proceed
without one.
That's why you do not have to write a default named query method. If you do write a default named
query method, make sure DevForce can find it by following the rules described here.
If you wrote a server-side query method, you must help DevForce find it, either by naming
the method in a way that conforms to DevForce conventions or by marking it with the
DevForce Query attribute.
Query naming conventions
DevForce can interpret query method names that begin with any one of the following
prefixes:
Prefix Method name example Matching EntitySet name
Get GetCustomers Customers
Query QueryCustomers Customers
Fetch FetchGoldCustomers GoldCustomers
Retrieve RetrieveStates States
Find FindWaldo Waldo
Select SelectCandidates Candidates
Using the Query Attribute
You don't have to follow the DevForce conventions when naming a specialized named query
or POCO query.
You must follow the DevForce convention when naming the default named query method.
You can name the query method as you please as long as you adorn it with the
Query attribute.
C#
[Query]
public IQueryable<Customer> ReturnAllCustomers() { ... }
[Query]
public IQueryable<Customer> GrabMeSomeGoldCustomers() { ... }
[Query]
public IEnumerable<State> BringBackTheStates() { ... }
VB
<Query()> _
Public Function ReturnAllStates() As IQueryable(Of Customer) ...
<Query()> _
Public Function GrabMeSomeGoldCustomers() As IQueryable(Of Customer) ...
<Query()> _
Public Function BringBackTheStates() As IEnumerable(Of State) ...
Now create the client query using the full server-side method name as the EntitySet name:
C#
var customersQuery = new EntityQuery<Customer>("ReturnAllStates", anEntityManager);
var goldCustomersQuery = new EntityQuery<Customer>("GrabMeSomeGoldCustomers",
anEntityManager);
var statesQuery = new EntityQuery<State>("BringBackTheStates", anEntityManager);
VB
Dim customersQuery = New EntityQuery(Of Customer)("ReturnAllStates", anEntityManager)
Dim goldCustomersQuery = New EntityQuery(Of Customer)("GrabMeSomeGoldCustomers",
anEntityManager)
Dim statesQuery = New EntityQuery(Of State)("BringBackTheStates", anEntityManager)
Other discoverability requirements
It isn't enough to name the method properly. You must also
Ensure the query method signature is appropriate for the root of the EntityQuery.
Define the method within a class marked by the EnableClientAccess attribute.
Locate that class in a discovered assembly.
Cache only queries
There are several techniques to help query and find entities in cache.


Finding entities in cache
The EntityManager provides several means of finding entities in its entity cache. In
DevForce-speak, "find" means to perform a search of cache only without attempting to access
the server or datastore.
Finding an entity by its EntityKey
If you know the EntityKey of an entity, you can use the FindEntity method to find the entity in
the EntityManager cache. This is an efficient way both to locate the entity or to prove that the
entity is not in cache.
C# Employee emp = (Employee) Manager.FindEntity(new EntityKey(typeof (Employee), 1));
VB
Dim emp As Employee = CType(Manager.FindEntity(New EntityKey(GetType(Employee), 1)),
Employee)

If the requested entity is not found a null (nothing) will be returned from the FindEntity call.
Note that the FindEntity call returns an object, so you must cast the returned object to the
entity type expected.
You can also use FindEntity to find an entity with an EntityState of Deleted. This is the only
means of locating an as-yet-unsaved deleted entity.
C#
var key = new EntityKey(typeof (Employee), 1);
Employee emp = (Employee) Manager.FindEntity(key), includeDeleted: true );
VB
Dim key = New EntityKey(GetType(Employee), 1)
Dim emp As Employee = CType(Manager.FindEntity(key), Employee), includeDeleted As Employee
Finding entities by EntityState
You can also look for entities in cache based on their EntityState. You can combine
EntityStates too, for example to look for all entities which are either Added or Modified.
FindEntities comes in both generic and non-generic forms, and will return either an
IEnumerable or IEnumerable<T>. If using the non-generic overload you can still cast the
results to an IEnumerable<T> in order to build a composable LINQ query.
C# var allAdded = manager.FindEntities(EntityState.Added);
VB Dim allAdded = manager.FindEntities(EntityState.Added)

C# var empList= manager.FindEntities<Employee>(EntityState.Unchanged);
VB Dim empList = manager.FindEntities(Of Employee)(EntityState.Unchanged)

Using LINQ you can do more interesting things with the results:
C#
var addedCustomersInUK = manager.FindEntities<Customer>(EntityState.Added).Where(c =>
c.Country == "UK");
// .. or ..
var addedCustomersInUK =
manager.FindEntities(EntityState.Added).OfType<Customer>().Where(c => c.Country == "UK");
VB
Dim addedCustomersInUK = manager.FindEntities(Of
Customer)(EntityState.Added).Where(Function(c) c.Country = "UK")
' .. or ..
Dim addedCustomersInUK = manager.FindEntities(EntityState.Added).OfType(Of
Customer)().Where(Function(c) c.Country = "UK")
Finding an object graph
The FindEntityGraph method allows you to search the entity cache for an object graph (aka
entity graph) - a list of entities that are navigable from one or more root entities according to a
specified graph. Working with an entity graph is particularly useful when performing a save
or import and you wish to work with only the object and its dependent entities.
The FindEntityGraph method takes one or more "root" entities, effectively the starting point
of the graph, and one or more EntitySpans , information about the entity relationships to be
followed to build the graph. The FindEntityGraph method also allows you to specify the
EntityState(s) wanted.
This sounds more complicated that it really is, so here's a simple example. Here we build an
entity graph of all orders and order details for a specific employee:
C#
var emp = Manager.FindEntity(new EntityKey(typeof(Employee), 1));
var span = new EntitySpan(typeof(Employee), EntityRelations.FK_Order_Employee,
EntityRelations.FK_OrderDetail_Order);
var entityGraph = Manager.FindEntityGraph(new[] { emp }, new[] { span },
EntityState.AllButDetached);
VB
Dim emp = Manager.FindEntity(New EntityKey(GetType(Employee), 1))
Dim span = New EntitySpan(GetType(Employee), EntityRelations.FK_Order_Employee, _
EntityRelations.FK_OrderDetail_Order)
Dim entityGraph = Manager.FindEntityGraph( { emp }, { span }, EntityState.AllButDetached)
Here's a more complex example. The EntityManager must be able to "walk" each EntitySpan,
in the case above we navigated from Employee -> Order -> OrderDetail. If a relationship
can't be walked, then you must supply another EntitySpan for it. Here we also want to retrieve
all Customers for the selected Orders. To do so we need to include another EntitySpan, one
which walks from Employee -> Order -> Customer.
C#
var emp = Manager.FindEntity(new EntityKey(typeof(Employee), 1));
var span1 = new EntitySpan(typeof(Employee), EntityRelations.FK_Order_Employee,
EntityRelations.FK_OrderDetail_Order);
var span2 = new EntitySpan(typeof(Employee), EntityRelations.FK_Order_Employee,
EntityRelations.FK_Order_Customer);
var entityGraph = Manager.FindEntityGraph(new[] { emp }, new[] { span1, span2 },
EntityState.AllButDetached);
VB
Dim emp = Manager.FindEntity(New EntityKey(GetType(Employee), 1))
Dim span1 = New EntitySpan(GetType(Employee), EntityRelations.FK_Order_Employee, _
EntityRelations.FK_OrderDetail_Order)
Dim span2 = New EntitySpan(GetType(Employee), EntityRelations.FK_Order_Employee, _
EntityRelations.FK_Order_Customer)
Dim entityGraph = Manager.FindEntityGraph( { emp }, { span1, span2 },
EntityState.AllButDetached)
A few more things to note.
The "roots" of the graph do not need to be of the same type.
Deleted entities can be included in the graph.
The "graph" is just an IList<object>, not a special type.
Entities not in cache are not lazily loaded when an association is navigated.
Synchronous queries in Silverlight
We've already seen that any query can be given a QueryStrategy to control where it's
executed. When you provide a CacheOnly query strategy, either explicitly on the query, by
setting the DefaultQueryStrategy on the EntityManager, or by disconnecting, the
EntityManager will run the query against the local entity cache only and not attempt to
communicate with the EntityServer. Since no server communication is performed, you can
execute CacheOnly queries synchronously in all environments, including Silverlight
applications.
For example, the following will work in any environment:
C# var customers = Manager.Customers.With(QueryStrategy.CacheOnly).Execute();
VB Dim customers = Manager.Customers.With(QueryStrategy.CacheOnly).Execute()

Or alternately,
C# var customers = Manager.Customers.With(QueryStrategy.CacheOnly).ToList();
VB Dim customers = Manager.Customers.With(QueryStrategy.CacheOnly).ToList()
You can also issue scalar "immediate" execution queries against cache only without using
AsScalarAsync . Here's a First method executed synchronously against cache:
C# var aCustomer = Manager.Customers.With(QueryStrategy.CacheOnly).First();
VB Dim aCustomer = Manager.Customers.With(QueryStrategy.CacheOnly).First()
In Silverlight you'll want to take care not to issue these synchronous queries without ensuring
that the query will indeed be executed against cache, since an error will be thrown otherwise.


Improve query performance
This page describes a number of ways to improve or optimize your query performance
within a DevForce application. It has been our experience however, that much, if not most of
the time, performance bottlenecks are not where a developer thinks they are. Premature
optimization often results in little or no performance gains for a substantial expense in time
and effort. We, therefore, strongly recommend that benchmarking be among the most
important tool you have in attempting to optimize the performance of your application. In
other words, benchmark before optimizing.
Logging
Among the most useful tools for determining if a query operation is taking too long is the
DebugLog. DevForce provides the DebugFns and TraceFns classes in IdeaBlade.Core
assembly that can be used to write out timings for any query.
It is often important to distinguish the amount of time spent actually executing the query on
the server from the amount of time spent transporting the results to the client and merging
them into an EntityManager's cache.
On the server, query interception and the EntityServerQueryInterceptor can be used as
interception points where both a query and the amount of time it takes to execute, on the
server, can be logged.
On the client, the EntityManager.Querying and EntityManager.Queried (see query-client-
lifecycle-events) events are good places to time the 'total cost' of a query.
Look at the SQL being executed
This can be accomplish either by turning on the ShouldLogSqlQueries option in the
IdeaBladeConfig.LoggingElement (see App.config in detail) or using a SQL profiler.
Microsoft's SQL profiler is an excellent tool for this task.
Profile the Entity Framework's performance
There are several tools available that profile Entity Framework performance. We recommend
EFProf.
Entity Framework performance tips
Since most queries within DevForce get translated into calls to the Entity Framework,
improving the performance of the Entity Framework query is an obvious first step. Several
techniques are available:
1. Entity Framework ViewGeneration is often the most time consuming part of the query
process. To determine just how much time spent here, you can use Microsoft's EDMGen tool
to pre-compile a query so that the expense of ViewGeneration becomes negligible at
runtime. (see http://msdn.microsoft.com/en-us/library/bb896240.aspx and
http://msdn.microsoft.com/en-us/library/bb387165.aspx )

2. Add Includes -(see Using Includes). Use of the Include method can have an enormous impact
on performance. In many n-tier applications the pipe between the client and the BOS is
among the slowest parts of the system and multiple round trips to a server can impose a
substantial performance burden. Judicious use of Includes can reduce the number of round
trips substantially.

3. Remove Includes -(see Using Includes). As useful as are and despite the possibility of using
them to improve performance; we have seen far too many examples of excessive use of
Includes. The problem is that every Include causes a minimum of one additional query to be
performed on the server. If this data is likely to be needed on the client within a relatively
short period of time then it often makes sense to reduce roundtrips by 'prefetching' this
data. However, if the data happens to not be needed on the server or is only needed in a
small number of use cases, then allowing this data to be fetched as needed ('lazy queries') is
often the much better choice.

4. Consider querying data asynchronously. Asynchronous queries operate on a separate thread
and their use can often make an application appear more responsive. This is really just
another form of 'eager querying', i.e. fetching the data before it is actually needed in the
expectation that it will 'probably' be needed. Use of coroutines can make writing collections
of asynchronous queries much easier.

5. Consider using Stored Procedure Queries or E-SQL queries instead of LINQ for queries in
some situations.

6. Consider using database views and mapping some of your entities to these views.

7. After ViewGeneration, metadata lookup is the next most time consuming part of the Entity
Framework. However, because metadata lookup is globally cached per Application Domain, it
only occurs once when the first query is passed to a DevForce Entity Server. Obviously, this
means that the cost of spinning up an EntityServer (which should occur rarely) can be
expensive. This is not usually a problem with distributed n-tier (and Silverlight) applications
because this effect is only felt once by the first user with his/her first query. However, when
testing 2-tier, the EntityServer runs as part of the client process and is spun up each time an
application restarts.

8. Consider breaking up your model into smaller submodels. Model's with more than 500 entity
types can be very cumbersome and both ViewGeneration and metadata lookup can be
expensive.

9. Favor TPH (Table per hierarchy) over TPT (Table per type) inheritance. (See the article,
'Performance Considerations when using TPT (Table per Type) Inheritance in the Entity
Framework'.)

10. Consider using Paging when returning large result sets. In some cases the time spent moving
large amounts of data over the wire can be drastically reduced by filtering the data returned
with the Take and Skip operators. (See Query Paging)


Create, modify and delete
Create, modify, and delete are things you do to entities while they are in memory.


Overview
You saw how to retrieve entities from the database in the Query topic.
Now that entities are in memory, you may want to modify them, delete them, and create new
ones - the three most important activities covered in this topic.
As you take these actions, your are making changes locally. These are pending changes,
visible only in the current client session. Even "deleted" entities are provisional; they are
merely scheduled for deletion. Your changes become permanent when you save them to the
database, a subject covered separately in the Save topic. Here we concentrate exclusively on
what you can do to entity instances while they are in memory.
We know you want to get right down to business and start changing entities. But first we have
to introduce a few fundamentals that run through the entire entity change discussion.
Entity cache
The entities in memory usually reside in an EntityManager's cache cache. When you query
for entities from the database, they go directly into cache. That's most likely how you'll get the
entities that you modify and delete. You can remove entities from the cache and manipulate
them while they are detached. Note that some entity feature are available only when an entity
is in cache ... which is where it should be unless you have a good reason to do otherwise.
Setting properties
Most of your changes involve setting data properties of the entity. It seems simple enough to
set a property with a statement like:
C# aCustomer.Name="Acme";
VB aCustomer.Name="Acme"


In fact, the setter of that innocent looking "Name" property is doing work under the hood that you
should know about as we'll see in the Set a property topic.
EntityState and EntityAspect
An entity's EntityState tells you whether an entity is in cache or not. If it is in cache, it tells
you if the entity has been changed or not ("Unchanged"). If it has changed, you'll want to
know if it is new ("Added"), modified ("Modified"), or scheduled for deletion ("Deleted").
Many of the things you do to an entity - actions described in this section - will change its
EntityState. Keep your eye on that EntityState.
Every entity has an EntityState but you won't see it listed among the entity's properties. You
will see an EntityAspect property that returns an EntityAspect object. The EntityAspect holds
the EntityState ... and exposes a goodly number of other members that concern the
intersection between the entity and the DevForce infrastructure. You'll need the EntityAspect
to get to some of the features discussed in this section.
Create
Create and manipulate a new entity that you intend to insert into the database.


Overview
Most applications can add new entities to the database. The essential steps are
1. Instantiate the entity object.
2. Set its unique EntityKey.
3. Initialize some properties as appropriate.
4. Add the new entity to an EntityManager.
Steps #1 and #4 are always required. Step #1 must come first; steps #2, #3, and #4 may occur
in any order.
You can write the code to create an entity in many ways. Some ways are more maintainable
than others. We'll recommend some practices as we describe the technical details.
Create the entity
Most developers create an entity by calling one of its constructors, perhaps the default
constructor which every entity must have.
C# cust = new Customer(); // the implicit default constructor
VB cust = new Customer() ' the implicit default constructor
Set the key
Every entity must have a unique EntityKey before it can be added to an EntityManager and
saved to the database. Key setting is a topic unto itself; you may have to generate keys with
custom code.
Initialize properties
Before you write code to initialize properties in a custom constructor, it helps to know how
DevForce initializes them first. You may not need to initialize properties in code.
We're talking about DevForce entity data properties. Your custom properties and POCO
entity initializations are up to you.
Standard default values
The data properties of a new entity return default values until you initialize them:
.NET primitive properties return their default values
o numeric properties return zero
o string properties return the empty string
o nullable struct properties (e.g., int? and Nullable(Of Integer)) return their null
instances.
ComplexType properties return ComplexType objects whose values are initialized as
described here.
Reference navigation properties return the null value until attached to an EntityManager;
then they behave like active navigation properties.
Collection navigation properties return an empty list until attached to an EntityManager;
then they behave like active navigation properties.
EDM default values
The Entity Data Model (EDM) may hold default values for some of the properties, values that
were derived from the database or entered manually through the EDM Designer. DevForce
uses these model default values instead of the usual defaults.
Custom default values
We can't set a default value for some data types, such as DateTime, in the Entity Data Model,
but we can still set a default at run time.
Set a default value function
You can modify or replace the DevForce-defined defaults by setting a DefaultValueFunction.
This is set once on the EntityMetadata class, and allows you to customize the default values
for data types throughout your model. This is particularly useful with DateTime and
DateTimeOffset data properties, since the DevForce defaults for these assume local time.
You can set only one DefaultValueFunction within your application.
Here's a sample which will return DateTime.Today with DateTimeKind.Unspecified as the
default value for any DataTime data property within your model, and allow DevForce defaults
to be used for all other data types.
C#
EntityMetadata.DefaultValueFunction = (t) => {
if (t == typeof(DateTime)) { return DateTime.SpecifyKind(DateTime.Today,
DateTimeKind.Unspecified); }
return EntityMetadata.DevForceDefaultValueFunction(t);
};
Set the DataEntityProperty.DefaultValue
You can also manually set the DefaultValue to be used on specific data properties. You need
to do this once only for the properties in question, and DevForce will then use these default
values when new entities are created.
For example, the following sets default values for several Employee data properties.
C#
Employee.PropertyMetadata.LastName.DefaultValue = "<Unknown>";
Employee.PropertyMetadata.BirthDate.DefaultValue = DateTime.SpecifyKind(DateTime.Today,
DateTimeKind.Unspecified);
Initialization precedence
In summary, the data property of a new DevForce entity is initialized as follows:
1. with the EDM default value if defined, or ...
2. with the standard or custom default value unless ...
3. the developer sets the initial value in code.
DevForce decides the default value in a "lazy" manner so you can take your time initializing
the property. DevForce settle upon the actual initial value when the property is first read.
Note that the initialization of default values for your properties is independent of how the
entity is created. You can use the CreateEntity method of the EntityManager or a simple
entity constructor.
Add to the EntityManager
You should add the entity to an EntityManager before making it available to the caller.
Navigation properties won't navigate until you do. Properties won't validate automatically.
You can't save an entity until its been added to an EntityManager.
Add the entity to the manager in one line:
C# manager.AddEntity(cust);
VB manager.AddEntity(cust)
You must have have set the EntityKey - or be using an auto-generated key - before you add the entity
to the manager as mentioned above.
Consider writing a constructor
DevForce does not generate an entity constructor. In many cases you can "new-up" the entity
using its default constructor, add it to the EntityManager, as we showed above.
This approach suffices in only the simplest cases. Many entities must satisfy specific invariant
constraints from the moment they're born. Some child entities should only be created by their
parents. Some entities have complex creation rules that you want to hide. Some entities
should never be created at all.
More often than not you will write a constructor.
Consider writing an entity factory
It may take only two lines to create an entity but it's rarely a good idea to repeat the same two
lines throughout your code base. Two lines have a way of becoming three, four and more. The
creation rules become fuzzy and you start to see Customer being created several different
ways for no obvious reason.
We urge you to wrap creation logic in factory methods - even if it is only two lines at the
moment. Then decide if the factory methods should be static members of the entity class or
instance methods of a separate entity factory class.
Different guidance applies when creating non-root members of an Aggregate. The mechanical details
of entity creation don't change but the way you arrange the code does change.
Write a custom constructor
You should write a custom constructor if any entity properties have required values.


Enforce invariant constraints in constructors
It's a best practice to ensure (to the degree possible) that a new entity is in a valid state. You
probably have business rules that stipulate which property values are always required and
what values they must have when they are created. The best place to enforce those rules is in
the entity constructor.
You should strive to have a valid entity at all times. You should feel a bit uncomfortable when
you can't reach that goal. For example, if a Customer is required always to have a real status
code, we might write this constructor:
C#
public Customer()
{
Status = InitialStatus;
}
VB
Public Sub New()
Status = InitialStatus
End Sub
One sure invariant: every entity must have an EntityKey. You should set the EntityKey in the
constructor unless it DevForce will be setting it automatically.
Don't initialize every property
Sometimes its better to leave properties alone. The Customer entity presumably has a Name
property. If the Customer name is allowed to be empty while in memory, don't initialize it.
This is a gray area. The customer name probably has a "is required" validation rule. You
won't be able to save the customer without a name. You could initialize it in the constructor
with a phony name such as "No Name". Technically the customer now passes the name-is-
required test. This isn't substantively better than a null or empty string and you risk polluting
the database with lots of "No Name" customers.

Most validation rules govern the state of the entity when it is saved. When a locally-invalid
entity is harmless and there is no satisfactory way to enforce the validity check, let it go.
On the other hand, when the validation rule expresses an invariant constraint - a constraint
that must be true at all times - then make sure you set the property value in the constructor.
When to use constructor parameters
Consider writing constructors that take required parameters when essential values can't be
determined within the constructor alone.
Imagine this time that a valid customer name is required at all times. It may never be null. The
constructor can't possibly know the actual name. Therefore, we require the name to be passed
in when creating the customer.
C#
public Customer(string name)
{
EnsureValidName(Name); // throws if null, empty, or bad
Name = name;
}
VB
Public Sub New(ByVal name As String)
EnsureValidName(Name) ' throws if null, empty, or bad
Name = name
End Sub
Ehy do we need "EnsureValidName"? Won't the property setter invoke validation and catch a
bad name? No it won't. Property setters validate input only when the entity is attached to an
EntityManager. This entity is not yet attached to an EntityManager. The EnsureValidName
method can validate the name using its own VerifierEngine if you wish.

A default parameterless constructor is required
When you add a constructor with parameters, you must also add a default parameterless
constructor. DevForce needs that default constructor.
DevForce materializes entities from query results. To "materialize" an entity, DevForce
"reconsititutes" it from server data. Sometimes DevForce can reconstitute it through a de-
serialization process that by-passes all constructors. In Silverlight, DevForce reconstitutes a
queried entity by calling its default, parameterless constructor.
Never assume that your constructor will be called when an entity is reconstituted by query ... or by
any other process. DevForce may or may not call the constructor. Don't guess.
In this example, Customer has a default constructor for entity reconstitution and a
parameterized constructor for entity creation:
C#
internal Customer() {} // required default constructor

public Customer(string name)
{
EnsureValidName(Name); // throws if null, empty, or bad
Name = name;
}
VB
Friend Sub New() ' required default constructor
End Sub

Public Sub New(ByVal name As String)
EnsureValidName(Name) ' throws if null, empty, or bad
Name = name
End Sub

Notice that there is no code inside the default constructor. The application will never call it. It exists
only to support reconsitution of an entity during a query. Don't put anything in the default
constructor unless you are sure to call it yourself.
Notice also that the default constructor is no longer public.
You can hide the default constructor
The implicit default constructor is public so DevForce and everyone else can call it. You may
not want everyone to call it.
You can hide the default constructor from other assemblies but you may not hide it from
DevForce. DevForce uses reflection to find the default constructor. If the entity is to be
accessible in Silverlight and you don't want the constructor to be public, you can mark
internal. You can't mark it private or protected because Silverlight won't let DevForce
discover it.
Access modifier constraints are explained elsewhere in connection with entity model
definition.

Don't add unnecessary constructor parameters
Minimize the number of constructor parameters and don't let them be optional. Use
constructor parameters only for values that absolutely must be passed in from outside.
You can set values for constrained entity properties within the constructor itself. You can set
optional properties from the outside, after constructing the instance.
Set the EntityKey in the constructor
Set the entity's unique EntityKey in the constructor unless it is store-generated or managed by
a custom key generator.



EntityKeys in brief
Every entity instances has an EntityKey that uniquely identifies and distinguishes it from
every other entity. The EntityKey also uniquely identifies the corresponding object in the
database.
You can't put an entity in an EntityManager cache until it has an EntityKey value. No two
entities with the same EntityKey value can coexist in an entity cache.
You can ask an entity instance for its EntityKey:
C#
var key = someEntity.EntityAspect.EntityKey;
var id = key.values[0];
VB
Dim key = someEntity.EntityAspect.EntityKey
Dim id = key.values(0)
An EntityKey instance holds one or more key values. Each is the value of a property of the
entity. That property is called a "key property". It was defined during the mapping exercise
when you built your EntityModel.
An entity class can have multiple key properties (a "composite key"); most entity classes only
have one key property, typically called the "ID".
Whether it's an ID or a composite key, your objective as a creator of entity objects is to set the
EntityKey as quickly as possible so that it can enter the cache and be displayed, modified and
saved.
You don't set auto-generated keys
You don't have to set the key if it is "store generated". An ID property mapped to an Identity
column of a table in SQL Server is a typical example of a store-generated EntityKey.
DevForce will initialize such a key for you.
In fact, you can't assign such a key and make it stick. DevForce will override your setting
with a temporary value the moment you add the entity to an EntityManager.
Similarly, if the entity requires a custom id, you'll have to wait until you add the entity to an
EntityManager before you initialize the key by calling EntityManager.GenerateId(...) as
described in the "Generate custom ids" topic.
You definitely want to wrap this complexity in a factory method.
If you don't have a store-generated key or a custom generated key, you must set the key
yourself and perhaps the best place to do that is in the constructor.
There are two ways to set the key: set it directly using a local key generator or set it using
parameters passed into the constructor.
Set a GUID key in the constructor
A GUID makes a fine key in part because it is easy to generate locally. You should set the
GUID key in the constructor.
C#
public Customer()
{
ID = SystemGuid.GetNewGuid();
}
VB
Public Sub New()
ID = SystemGuid.GetNewGuid()
End Sub
You ask "What is SystemGuid.GetNewGuid()? There is no SystemGuid class in .NET !"
Right you are. SystemGuid is a utility class that you should consider adding to your
application because it helps you control what kind of Guid you create and makes it easier to
write repeatable tests of your entity creation logic.
Set a key with constructor parameters
Sometimes the key for the new entity should be the same as the key of another entity. This
typically happens when a root entity has an optional companion that extends the root with
extra information.
The companion is a "dependent" entity in a one-to-one relationship with its parent "principal"
entity. The companion's key is always the same as its parent's key.
The principal entity usually maps to one table in the database and the dependent entity to a different
table. You could model them together as a single conceptual entity in Entity Framework. However,
practical reasons may oblige you to model them as separate entities as we're doing in the following
example.
Suppose we have a Customer entity and a CustomerExtra entity. Maybe the CustomerExtra
carries a potentially giant image of the Customer. The Customer entity is lean and light so you
can afford to retrieve lots of Customer entities. You don't worry about the cost of the image.
You only need the image when the user drills-in for more detail about the customer; that's
when you'll retrieve its companion CustomerExtra.
The Customer entity is the principal, CustomerExtra is the dependent, and you can navigate
between them via their reciprocal reference properties. CustomerExtra's ID is always the same
as its parent Customer's ID.
The CustomerExtra constructor needs one parameter, the parent customerID. It might look
like this:
C#
public CustomerExtra(int parentCustomerID)
{
CustomerID = parentCustomerID;
}
VB
Public Sub New(ByVal parentCustomerID As Integer)
CustomerID = parentCustomerID
End Sub
Set composite keys with constructor parameters
A "linking" entity associates two other entities in a many-to-many relationship. The
Northwind OrderDetail entity has a key with two parts, a composite key.
One part is the ID of the parent Order. The other is the ID of the associated product, the
product being purchased. the two parts of the key are simultaneously the foreign key ids
supporting the navigation properties - OrderDetail.Order and OrderDetail.Product.
The OrderDetail has to have a complete composite key - both ids - before it can be added to
an EntityManager. These ids can't be calculated; they are invariants supplied at the moment of
creation.
The constructor could look like this.
C#
public OrderDetail(int parentOrderID, int productID)
{
CustomerID = parentCustomerID;
ProductID = productID;
}
VB
Public Sub New(ByVal parentOrderID As Integer, ByVal productID As Integer)
CustomerID = parentCustomerID
ProductID = productID
End Sub


Consider entity parameters instead of ids
In the previous example, the constructor parameters were the ids of related entities. The caller
of the OrderDetail constructor would probably extract the ids from the parent Order and
Product and "new" an OrderDetail like so:
C# var newDetail = new OrderDetail(anOrder.ID, aProduct.ID);
VB Dim newDetail = new OrderDetail(anOrder.ID, aProduct.ID)


There are times when when this kind of constructor is useful ... even necessary. More often it is
better to pass the entities rather than ids.
First, it's usually easier on the caller who has the Order and Product entities in hand. The
caller doesn't have to bother with or even know about their idss; it just passes Order and
Product.
C# var newDetail = new OrderDetail(anOrder, aProduct);
VB DIm newDetail = new OrderDetail(anOrder, aProduct)


And it lets the alternative constructor do the dirty work:
C#
public OrderDetail(Order parentOrder, Product product)
{
EnsureOrderAndProductAreGood(parentOrder, product);
OrderID = parentOrder.ID;
ProductID = product.ID;
}
VB
Public Sub New(ByVal parentOrder As Order, ByVal product As Product)
EnsureOrderAndProductAreGood(parentOrder, product)
OrderID = parentOrder.ID
ProductID = product.ID
End Sub
The more important reason to prefer passing entities is that it enables richer input validation.
The "Ensure..." method can do more than check for null. It can validate the Order and the
Product; make sure they're well matched; make sure that the Order is valid for this detail (and
vice versa).
Lesson: prefer constructors with entity parameters.
Postpone adding to manager
The constructor could have set the Order and Product reference navigation properties instead
of setting the corresponding foreign key ids. The implementation might have been this:
C#
public OrderDetail(Order parentOrder, Product product)
{
EnsureOrderAndProductAreGood(parentOrder, product);
Order = parentOrder;
Product = product;
}
VB
Public Sub New(ByVal parentOrder As Order, ByVal product As Product)
EnsureOrderAndProductAreGood(parentOrder, product)
Order = parentOrder
Product = product
End Sub
But it wasn't. The author chose to set the ids instead of the navigation property because he
didn't want to add a new OrderDetail to an EntityManager just yet.
The author understood that if he set the navigation property - the Order property in this case -
DevForce would immediately add the OrderDetail to the EntityManager of the parent Order.
That's the expected behavior described in the "Add, attach, and remove" topic. He did not
want to add it to a manager.
Perhaps the author was hoping use this constructor in OrderDetail tests. Perhaps he planned to
create design-time OrderDetail entities inside Blend. Testing and designing are easier if the new
OrderDetail is attached to an EntityManager in the manner of a pre-exising entity rather than added
as a new entity . He kept these options open.



Create a factory method
As you start to write your entity creation code, you'll wonder "where do I put it?". Where
you put it does matter. We strongly recommend that you use a factory method. Beyond that,
you have choices, each with its pros and cons. We cover some of the choices and
considerations in this topic.



Introduction
Where do you put the code that creates an entity? It depends on the entity, the circumstances,
and you're preferred style. You have to make your own choices. We'll suggest some ways to
think about the choices in this topic.
Whatever you decide to do, we urge you to create entities within a factory method.
Use a factory method
A "factory" method is a method that creates an object.
We strongly discourage sprinkling bare creation logic about your code base. You don't want
to find a line like this in your application.
C# new Customer(); // more to follow
VB New(Customer() ' more to follow
This firm advice applies even if a perfectly well formed Customer is easy to create that way.
Sure it is tempting. It is acceptable inside test methods and wherever you create test entities.
But don't do this anywhere in the application code base.
Why? Because it never stays this simple. Over time, you and other developers will find
multiple, conflicting ways to create a customer that ruin your chances of a consistent,
maintainable application. Just say "no".
Here's a simple factory method:
C#
public Customer CreateCustomer()
{
return new Customer(); // more to follow
}
VB
Public Function CreateCustomer() As Customer
Return New Customer() ' more to follow
End Function
It bears repeating
Do encapsulate creation logic in a factory method

"New" the entity; avoid "CreateEntity(...)"
We recommend that you instantiate the entity with "new" as seen throughout this topic.
DevForce offers an alternative approach using the entity factory build into the EntityManager.
The previous example could have been written:
C#
public Customer CreateCustomer(EntityManager manager)
{
return manager.CreateEntity<Customer>(); // more to follow
}
VB
Public Function CreateCustomer(ByVal manager As EntityManager) As Customer
Return manager.CreateEntity(Of Customer)() ' more to follow
End Function
Although this approach requires the help of an EntityManager, it doesn't actually add the new
Customer to the manager. It differs from "new" in these respects:
1. It uses the default constructor internally to instantiate the entity
2. It initializes the entity data properties with the default values defined in the Entity Data
Model (if any) but only if the default constructor didn't change them first.
3. It hides a (replaceable) reference to the EntityManager inside the created entity.
Consider a factory without "AddToManager"
The following is advice that stems from a design-friendly and test-oriented mentality.
Remember that adding the new entity to an EntityManager is one of the critical steps to
creating an entity. You won't be able to do much with your entity until you take that last step
and add the entity to an EntityManager. You won't forget that step if you include it in the
factory method:
C#
// This is ok
public Customer CreateCustomer(EntityManager manager)
{
if (null == manager) { /* throw exception */ }
var cust = new Customer();
// other stuff
manager.AddToManager(cust);
return cust;
}
VB
' This is ok
Public Function CreateCustomer(ByVal manager As EntityManager) As Customer
If Nothing Is manager Then ' throw exception
End If
Dim cust = New Customer()
' other stuff
manager.AddToManager(cust)
Return cust
End Function
It's ok but it's not a best practice because it combines two distinct concerns: (1) making a valid
Customer and (2) integrating with the DevForce infrastructure. That makes entity creation
harder to test than it should be. I can't evaluate my Customer creation rules without providing
an EntityManager - a requirement that has nothing to do with what I'm trying to test. It also
complicates the visual design process in XAML platforms because adding an entity to an
EntityManager may be blocked in Blend.
Consider breaking the CreateCustomer method into two overloads:
C#
// Can create without adding to manager
public Customer CreateCustomer()
{
var cust = new Customer();
// other stuff
return cust;
}

public Customer CreateCustomer(EntityManager manager)
{
if (null == manager) { { /* throw exception */ }
var cust = CreateCustomer();
manager.AddToManager(cust);
return cust;
}
VB
' Can create without adding to manager
Public Function CreateCustomer() As Customer
Dim cust = New Customer()
' other stuff
Return cust
End Function

Public Function CreateCustomer(ByVal manager As EntityManager) As Customer
If Nothing Is manager Then ' throw exception
Dim cust = CreateCustomer()
manager.AddToManager(cust)
Return cust
End If
Consider intention-revealing factory methods
In many applications you intentionally create different versions of the same type of entity.
You might create "Gold Customers" and "Silver Customers" and "Platinum Customers".
You're always creating Customer entities but you configure each variation differently.
Perhaps they differ only in a few property values. They could differ more substantially as
when creating a "Platinum" customer triggers a sequence of ancillary activities and entity
creations that are not available to "Silver" Customers. It might take more information - more
and different parameters - to create a "Platinum" customer than a "Silver" customer.
Why not create different factory methods for each variation?
C#
public Customer CreateSilverCustomer(p1, p2) {}
public Customer CreateGoldCustomer{p1, p2, p3) {}
public Customer CreatePlatinumCustomer{p1, p4, platinumOptions) {}
VB
Public Customer CreateSilverCustomer(p1, p2)
End Sub
Public Customer CreateGoldCustomer(p1, p2, p3)
End Sub
Public Customer CreatePlatinumCustomer(p1, p4, platinumOptions)
End Sub
The names express the difference clearly and in business terms. Each method can be tailored
to its purpose, as complex or as simple as it needs to be. You can add as many Create methods
as you want and add more over time without fear of breaking the core Customer class.
You don't dare do this with different constructor overloads. Constructors can only have one
name (the name of the class). Multiple overloads are confusing. You shouldn't change the
Customer class everytime you dream up a new flavor of Customer. Keep constructors lean.
They should enforce the invariant constraints of the entity and little else.
Generate custom ids
You have to write a custom id generator when a new entity's permanent key must be
calculated with information only accessible on the server. This topic covers how to write an
implementation of the DevForce IIdGenerator interface for that purpose.


Overview
Every newly created entity requires a permanent unique key to be stored in the database. The
key could be generated by the database or it could be assigned in creation code on the client
(e.g, with a GUID). These are the simple cases covered in the entity creation topic.
Sometimes you have to calculate the key on the middle tier server. The database can't
generate it and you can't determine it on the client because a critical ingredient in your key
definition scheme is only accessible on the server. You'll have to write a custom id generator.
Your custom id generator is a class that implements the DevForce
IdeaBlade.EntityModel.IIdGenerator. You deploy this class on both the server and the client
and let DevForce discover it.
A scenario
Imagine that your application data are stored in a legacy relational database. The tables have
integer key columns but key values are not store-generated ... and you are not allowed to
modify the database so that they can be store-generated.
Instead, the database has a special table of ids called the NextId table. It has a single row
and a single column holding the next available integer id. To get a new id, you'll have to read
the current "next id" value, increment the "next id" value in the table, and save. Of course
you'll have to worry about concurrency; you must prevent some other process from reading
the same "next id" value or overwriting your "next id" value. So you either lock the table or
perform these operations within a transaction.
You can't let remote clients perform this operation even if they could. The contention for that
one precious "next id" value would be enormous. There are many potential clients. There is
only one or maybe a few servers. We'll have to let the server(s) manage the "next id".
You put the code to manage the "next id" in your custom id generator class.
An example
Most tables in the NorthwindIB tutorial database that ships with DevForce are defined with
store-generated integer ids. The Territory table does not. If you map a Territory entity to the
Territory table, it will have an integer id property ("TerritoryID") that you'll have to manage
with a custom id generator.
The NorthwindIB tutorial database also has a NextId table. The "Custom Id Code
Generation" code sample [LINK] includes a custom id generator class that uses this table to
calculate permanent ids.
You would not map the NextId table to a "NextId" entity nor use Entity Framework to maintain that
table. You would use raw ADO.NET commands as illustrated in the code sample.
We refer to Territory and the NextId table throughout this topic.
Temporary ids
In principle, the client could ask your server-side id generator for the "next id" every time it
created a new entity. That would be inefficient. It won't work at all if the client is
disconnected from the server. DevForce is designed to work disconnected.
We have to be able to create new entities without accessing the server. The solution is to use
temporary ids and replace them with permanent ids before save.
Accordingly, when you create a new entity, you give it a key with a temporary id. More
precisely, you tell a DevForce EntityManager to give the new entity a temporary id as shown
in this example of a static Create method for Territory.
C# public static Territory Create(
EntityManager mgr,
string territoryDescription, int regionID)
{
Territory newTerritory = new Territory();

mgr.GenerateId(newTerritory, Territory.PropertyMetadata.TerritoryID);

// other code

newTerritory.EntityAspect.AddToManager();
return newTerritory;
}
VB Public Shared Function Create( _
ByVal mgr As EntityManager, _
ByVal territoryDescription As String, ByVal regionID As Integer) As Territory

Dim newTerritory As New Territory()

mgr.GenerateId(newTerritory, Territory.PropertyMetadata.TerritoryID)

' other code

newTerritory.EntityAspect.AddToManager()
Return newTerritory
End Function
The critical line is the GenerateId method of the EntityManager ("mgr") where we supply the
new Territory entity ("newTerritory") and identify the property that gets the generated id.
C# mgr.GenerateId(newTerritory, Territory.PropertyMetadata.TerritoryID);
VB mgr.GenerateId(newTerritory, Territory.PropertyMetadata.TerritoryID)
We have to tell the GenerateId method which property to generate. The key could be a composite
made up of multiple properties. DevForce can't guess which of those properties requires a temporary
id. If the key consisted of two id properties, both of them custom generated, we'd have to make two
calls to GeneratId, each identifying the property to set.
How does DevForce know what temporary id value to assign? DevForce doesn't know. Your
custom id generator does. You specify how to create a temporary id in the GetNextTempId
method of your generator. The DevForce GenerateId method calls your GetNextTempId and
remembers that temporary id in the TempIds collection that you also implemented in your
generator.
NorthwindIB Territory ids are always positive integers. A negative integer is a good candidate
as a temporary id. We pick an arbitrary seed (such as -100) and decrement it each time we
need a new id.
Let's suppose that your generator returned a temporary id of -101 and that the EntityManager's
GenerateId method assigned -101 to the "newTerritory" entity.
The "newTerritory" entity can carry that value around as long as it stays on the client. We'll
only have to replace it with a permanent id when we save it. More on that soon.
Temporary foreign key ids
NorthwindIB has an EmployeeTerritory table which associates Employees and Territories in a
many-to-many relationship.
EmployeeTerritory has a "Territory" navigation property that returns the related Territory
entity. It also has a "TerritoryID" property which holds the id of that related Territory entity.
"TerritoryID" is a foreign key id ("FK Id") property.
Suppose we had an instance of EmployeeTerritory called "someEmpTer" and we set its
"Territory" property with with "newTerritory".
C# someEmpTer.Territory = newTerritory;
VB someEmpTer.Territory = newTerritory
Now we have -101 in two places: once as the primary key of "newTerritory" and again in the
FK id of "someEmpTer".
Everything is fine until we save. Before we can save, we'll have to replace the -101 values in
both places with the permanent id for "newTerritory" ... an id value we don't have yet.
Id Fix-up
DevForce replaces all temporary id values with permanent values when we finally ask the
EntityManager to save the changes. This process is called "Id Fix-up", and occurs during the
save.
In the fix-up process:
DevForce on the client sends the temporary ids to the EntityServer, along with all entities to
be saved.
The EntityServer asks your custom id generator's GetRealIdMap method to produce a
dictionary of temporary/permanent id pairs.
Your GetRealIdMap gets the permanent ids (perhaps from a NextId table as discussed earlier)
and pairs them with the temporary ids, and returns this dictionary.
The EntityServer uses this mapping of temp-to-perm ids to perform a fix-up on entities to be
saved, and then performs the save.
The EntityServer returns the temp-to-perm id map to the client, along with the saved
entities.
DevForce merges the saved entities into the client's cache, using the temp-to-perm id map
for guidance.
DevForce tells your client-side id generator to reset itself and clear the list of temporary ids.
You don't have to wait for save to fix-up the ids. You can call the EntityManager's ForceIdFixup (or
ForceIdFixupAsync) methods any time.
Observations
The NextId table is a familiar example that comes in many variations. In NorthwindIB there is
a single "next id" value for all entities that need custom id generation. Another database might
have different "next id" values for each entity type.
Your application might not have a NextId table. It might have some other source of "next id"
values. The commonality running through all custom id generators is that id calculation
depends upon an external resource that can only be accessed on the server.
An application could have a mix of id generation strategies. Most of the NorthwindIB tables
have auto-increment (identity) columns that don't require the attention of your custom id
generator. Territory is the exception.
Perhaps you noticed that DevForce calls some id generator methods on the server and calls
others on the client (and it calls a few members on both tiers). The specifics are detailed in the
API documentation.
Most developers will write one class and deploy it to both the client and the server. The
easiest way to deploy it is simply to include it in the same project as your entity classes; you'll
deploy that project to both client and server anyway.
If the single-class approach is not to your liking, you can write two classes that implement the
IIdGenerator interface, one for the client and one for the server. It's up to you to ensure that
they are compatible.
You don't have to reference the custom id generator class in any of your projects. DevForce
will discover it using its MEF-based extensibility mechanism.
Sample Id Generator
See the code samples for the source code of an example numeric id generator class that you
can either use directly or adapt for your application
Block entity creation with an internal constructor
You may want to prevent application developers from creating new instances of certain entity
types. You will need a "defense in depth" on both client and server to block the determined
developer. In this topic we suggest that you block entity construction by making all
constructors internal.


Fixed-set entity types
In every application there are "fixed-set" entity types. The number of states in the USA is fifty
and that is not expected to change. If U.S. states are modelled as entities, you want to make it
difficult to add a new state by accident.
You probably want to prevent modifications and deletions too, subjects covered elsewhere [LINK].
It's a good idea to add a save interceptor rule [LINK] that rejects any client's attempt to save
a change to a U.S. State or to alter the set of U.S. states.
Unfortunately, a developer won't know that changes are forbidden until runtime when the
application throws an exception. If you make the entity difficult to construct in the first place,
the developer won't be tempted to make a mistake.
Write an internal default constructor
Consider writing an internal default constructor. Make all other constructors internal as well.
C# internal UsaState() { } // Do not create new states
VB
Friend Sub New() ' Do not create new states
End Sub
In Silverlight application you must use internal, not private or protected. DevForce has to
"materialize" UsaState objects retrieved by a query. Conceptually queries reconstitute existing
entities; they don't create new entities. In practice, "materialization" may involve calling a class
constructor. DevForce can call an entity's internal constructor; it can't call a private or protected
constructor in Silverlight.
Leave a back-door
Make it difficult to create an entity but not impossible. You don't want to query for test
entities and you can't query for design entities. You need a back-door to create them in
memory and make it look like you queried for them - a technique covered elsewhere [LINK].
The internal constructor may be sufficient.
Alternatively, you can add a static CreateForTest method to the entity class that is clearly
limited in intent. Surround it in compiler directives to ensure it doesn't show up in your
release builds.
C#
#if DEBUG
///<summary>Internal use only</summary>
public static UsaState CreateForTest
{
return new UsaState();
}
#endif
VB
#If DEBUG Then
'''<summary>Internal use only</summary>
Public Shared ReadOnly Property CreateForTest() As UsaState
Return New UsaState()
End Property
#End If

Replace temporary foreign key ids with permanent ids
This topic explains how DevForce replaces temporary foreign key id values with permanent
ids during id fix-up. Foreign key id fix-up is phase withing the larger fix-up process. This
topic is only relevant when ids are generated by the database or by a custom id generator.


Foreign Key Ids
When two entities are related, the dependent entity (child entity) holds the key of the related
principal entity (parent entity) in a foreign key property.
For example, suppose an Order entity is related to a parent SalesRep entity. SaleReps have
many orders. An Order has one parent SalesRep. The Order entity has a SalesRepID foreign
key property that holds the ID of the parent SalesRep who took the order.
Let's create a SalesRep called "newSalesRep". Assume that the key of the SalesRep entity is a
store-generated integer id. When we create a new SalesRep, DevForce assigns it a temporary
id automatically. That temporary id will be a negative integer. Let that temporary id be -101.
Now let's create an Order called "newOrder" and set its navigation property to
"newSalesRep".
C# newOrder.SalesRep = newSalesRep;
VB newOrder.SalesRep = newSalesRep
Setting the SalesRep navigation property for "newOrder" also sets its SalesRepID property.
The SalesRepID value will be -101, the same as the temporary id of "newSalesRep".
Fix up
The application begins to save these new entities. Because temporary ids have been generated,
the fix-up process begins. The permanent id for the "newSalesRep" is determined; let's
suppose the value is 300.
The fix-up process knows about relationships between the SalesRep and other entities. In
particular, it knows about SalesRep's relationship with Order and it knows about Order's
SalesRepID.
Accordingly, it finds the "newOrder" and replaces its current SalesRepID value of -101 with
300, the permanent id of "newSalesRep". "newOrder" has been fixed-up and is ready to be
saved to the database.
This all happens automatically.
Fix up failure
All works fine as long as every entity relationship is defined in the DevForce metadata. Such
will be the case when the DevForce entity classes are generated from an Entity Framework
Entity Data Model (EDM) which accurately reflects every pertinent foreign key relationship
in the database.
There is usually nothing to worry about. But it is possible to omit a relationship, especially if
that relationship is not enforced by foreign key constraints in the database.
The telltale sign of a problem is negative values in foreign key id columns of the database.
Let's extend our previous example. Suppose that Customers are also assigned to SalesReps.
The SalesRep is the parent and the Customer is the child in this relationship. Therefore, the
Customer entity carries a SalesRepID that points to its parent SalesRep.
Customer parallels Order in this regard ... except in one detail.
DevForce doesn't know that Customer and SalesRep are related. For some reason there is no
association between them. Customer has a SalesRepID property but no known relation to
SalesRep and no navigation property to SalesRep either. It just has the SalesRep's id.
A missing relationship is a critical omission, as we will see.
This time we'll start with an existing Customer, held in a variable called "aCustomer". We're
intent on reassigning this customer to the "newSalesRep" which we just created.
Although there is no SalesRep navigation property, we are determined to establish the
association implicitly by setting "aCustomer"'s SalesRepID directly.
C# aCustomer.SalesRepID = newSalesRep.Id;
VB aCustomer.SalesRepID = newSalesRep.Id
The absence of the myCustomer.SalesRep navigation property should have been a warning that a
critical relation might be missing.
Let's see replay the fix-up scenario with this new twist:
The value of newSalesRep.ID is updated to its permanent value, 300.
newOrder.SalesRepID is fixed up to 300 because there is a relation between Order and
SalesRep.
aCustomer.SalesRepID retains the temporary id = 101 because there is no relation between
Customer and SalesRep; fix-up doesn't know it should replace aCustomer's SalesRepID.
Only bad things can happen as DevForce continues trying to save these entities.
If the database schema actually has a foreign key constraint on the Customer's SalesRepID
column, the save will fail with an exception because the database can't find a SalesRep with
the negative id = -101.
If there is no foreign key constraint, "aCustomer" will be written to the database with a
negative SalesRepID = -101. That is a data integrity violation even if there is no code or
database constraint to catch it.
Important: Map all entity relations.
Use CreateEntity() sparingly
While we recommend using "new" to create the entity within a factory method, the
CreateEntity factory is available and merits some consideration. This topic describes it, when
you might want to use it, and why you probably don't.


Using "new"
We generally recommend that you call a constructor within a factory method when creating a
new entity ... as we typically do throughout this documentation. Here's a simple factory
method that uses "new".
C#
public Customer CreateCustomer()
{
return new Customer(); // more to follow
}
VB
Public Function CreateCustomer() As Customer
Return New Customer() ' more to follow
End Function
Introducing CreateEntity(...)
DevForce offers an alternative approach that uses the CreateEntity factory method of the
EntityManager. Here's the same example - or close to it - written with CreateEntity:
C#
public Customer CreateCustomer(EntityManager manager)
{
return manager.CreateEntity<Customer>(); // more to follow
}
VB
Public Function CreateCustomer(ByVal manager As EntityManager) As Customer
Return manager.CreateEntity(Of Customer)() ' more to follow
End Function
Although this approach requires the help of an EntityManager, it doesn't actually add the new
Customer to the manager. You have to do that in a separate step. It differs substantively from
"new" in these respects:
1. It uses the default constructor internally to instantiate the entity
2. It hides a reference to the EntityManager inside the created entity.
Many of us fail to see the advantage of these differences.
It's often inappropriate or impossible to create a new entity with a default constructor as
discussed in the topic on writing a custom constructor.
The embedded EntityManager is hidden, silent, and (mostly) inaccessible until after the
entity is added to cache.
The hidden EntityManager
The CreateEntity method embeds an EntityManager within the new entity. It's presence
enables the following technique for adding the entity to the EntityManager:
C#
cust.EntityAspect.AddToManager();

VB cust.EntityAspect.AddToManager()
You can't call AddToManager on an entity you created with "new". You have to write:
C#
manager.AddEntity(cust);

VB manager.AddEntity(cust)
The embedded EntityManager is otherwise inaccessible as demonstrated in these tests:
C#
var cust == manager.CreateEntity<Customer>(); // hides an EntityManager inside the entity
Assert.IsNull(cust.EntityAspect.EntityManager); // EntityManager is not visible
cust.EntityAspect.AddToManager(); // adds the entity to the hidden EntityManager
Assert.IsNotNull(
cust.EntityAspect.EntityManager()); // now you see it.
VB
Dim cust = manager.CreateEntity(Of Customer)() ' hides an EntityManager inside the entity
Assert.IsNull(cust.EntityAspect.EntityManager) ' EntityManager is not visible
cust.EntityAspect.AddToManager() ' adds the entity to the hidden EntityManager
Assert.IsNotNull(cust.EntityAspect.EntityManager()) ' now you see it.
Generalizing entity creation with the non-generic overload
The non-generic overload of CreateEntity has potential in a few scenarios. It could be
convenient if you were writing a general utility that created entities as one of its duties.
C#
public object CreateUserSelectedEntity(EntityManager manager, Type entityType)
{
var anEntity = manager.CreateEntity(entityType);
// do something with it
return anEntity;
}
VB
Public Function CreateUserSelectedEntity(ByVal manager As _
EntityManager, ByVal entityType As Type) As Object
Dim anEntity = manager.CreateEntity(entityType)
' do something with it
Return anEntity
End Function
It is modestly difficult to "new" a class when you don't know its type. The DevForce
CreateEntity method does it without ceremony.
Conclusion
Stick with "new" unless you are writing an entity creation utility.

Modify
Modify entities in the entity cache.


Overview
Modifications to your entities in cache is a straightforward process. You've loaded entities
into the EntityManager cache - usually by querying for them, but also by creating and saving
new entities, importing entities from another EntityManager, and by loading a previously
saved snapshot.
However the entities got there, you can then modify them as needed. These modifications will
often be through your UI via data binding to the properties of your entities, allowing user
changes to be pushed into the properties.
To persist your changes to the data store, you'll call one of the SaveChanges overloads on the
EntityManager.
The generated setter
Most properties of your entities have public getters and setters. You've set the access in the
EDM Designer, and the generated code has dutifully carried out your wishes:
C#
public string CompanyName {
get { return PropertyMetadata.CompanyName.GetValue(this); }
set { PropertyMetadata.CompanyName.SetValue(this, value); }
VB
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
}
When the property is data bound, both its getter and setter will be invoked to retrieve and set
the value.
To change a property value, you'll generally use the property setter,
C# myCustomer.CompanyName = "Emeryville Eats";
VB myCustomer.CompanyName = "Emeryville Eats"
.
The first modification to an unchanged entity causes its EntityState to become Modified. If
you're working with a newly created entity, its EntityState will remain as Added. Use the
EntityAspect for the entity to see its current state.
Every time a property is modified DevForce will automatically raise a PropertyChanged
event for the specific property name. Data bound controls will listen for these events to
refresh the display.
We saw the set pipeline in the "get and set a property" topic. Along with BeforeSet and
AfterSet property interception, validation may be performed, and a number of events are
raised in addition to PropertyChanged.
Miscellaneous topics
Thread safety
Like the EntityManager, an entity is not thread-safe. Unlike the EntityManager, DevForce
won't try to detect that the entity is being used on multiple threads. So if you decide to have a
background worker massage your entities while the application user is editing them in the UI,
you're writing your own recipe for disaster. If you need to use an EntityManager and its
entities across threads, the best thing to do is import the entities into another manager, so that
each thread has its own EntityManager to work with.
Modifying EntityKey properties
Once at entity has been created and saved, you cannot modify its EntityKey. You'll receive an
exception when saving the change if you try. If you do find you need to modify the key, you
can clone the original entity, set the new EntityKey and add the clone to the EntityManager,
and delete the original entity.
All entities implement ICloneable via an explicit interface implementation, so you must first
cast the entity to ICloneable, for example:
C# Customer customerCopy = ((ICloneable)aCustomer).Clone() as Customer;
VB

Customer customerCopy = ((ICloneable)aCustomer).Clone() as Customer
Changing concurrency properties
Concurrency property values are often set by the data store - for example via a database
trigger or a timestamp column - or with the DevForce "auto" settings. But you can also set
the new concurrency value in your application code. Just remember to set the
ConcurrencyStrategy to Client, and you can then set the property value as wanted, for
example:
C# aCustomer.LastChangeDt = DateTime.Now.ToUniversalTime();
VB aCustomer.LastChangeDt = DateTime.Now.ToUniversalTime()

Delete
Similar to modifying an entity, deleting an entity is a two step process. You first mark the
entity for deletion in the EntityManager's cache, and then you commit the changes to the
datasource.
Mark an entity for deletion
You mark an entity for deletion by calling EntityAspect.Delete.
C# product.EntityAspect.Delete();
VB product.EntityAspect.Delete()
After calling Delete, the EntityState will be set to Deleted.
Commit changes to the datasource
The entity will be deleted from the datasource when you call EntityManager.SaveChanges.
After a successful SaveChanges, the EntityState will become Detached and the reference to
the entity is no longer valid and it should not be used.
You should remove the 'deleted' entity from any lists and UI datasources before calling SaveChanges.
Otherwise, any logic that operates on the entity will likely throw an exception.
Delete a new entity
Calling Delete on a newly created entity (one that has not been saved) will immediately
discard the entity since it does not exist in the datasource.
Undo an entity marked for deletion
If an entity is marked for deletion, you can call EntityAspect.RejectChanges to undo the
scheduled deletion. (You can also call EntityManager.RejectChanges to revert everything in
the cache.) Once SaveChanges is successfully called, you can no longer reject the changes,
and another save will be required to modify the datasource. To learn more about undoing
changes in the client-side cache see Undo changes.
Cascaded deletes
If the Entity Data Model and the database have been configured to handle cascaded deletes,
other dependent entities may be deleted as well. For example, deleting an Order may also
result in the deletion of all of its OrderDetails. See Handle cascaded deletes for more
information.
Other technical considerations
If you access the properties of the deleted entity, they will be the original values as they were
queried from the datasource, as this represents the entity that is being deleted.
Get and set a property
When you get or set an entity property, DevForce includes a pipeline of actions which you
can intercept.


When you created your model you specified the names of entity properties and their
attributes, such as visibility. The generated code reflects your choices. Let's examine the
generated property in more depth.
Data properties
The DataEntityProperty represents either a "simple" property, one in which the data type is a
simple primitive such as int or string, or a "complex" property, a ComplexObject containing
other simple and complex properties. For example:
C#
public string CompanyName {
get { return PropertyMetadata.CompanyName.GetValue(this); }
set { PropertyMetadata.CompanyName.SetValue(this, value); }
}
VB
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 salient point is that in place of a simple backing field or automatic property we see
GetValue and SetValue calls on a metadata property.
We saw in the model topic how a PropertyMetadata class is generated into each entity class to
hold static definitions of all properties of the entity:
C#
public static readonly IbEm.DataEntityProperty<Customer, string> CompanyName =
new IbEm.DataEntityProperty<Customer, string>(
"CompanyName", false, false, IbEm.ConcurrencyStrategy.None, false);
VB
Public Shared ReadOnly CompanyName As New IbEm.DataEntityProperty(Of _
Customer, String)("CompanyName", False, False, IbEm.ConcurrencyStrategy.None, False)
It's the DataEntityProperty which controls how the get or set is performed. When the
DataEntityProperty is constructed, it populates its GetterInterceptor and SetterInterceptor,
which control the get and set pipelines respectively. You won't often work directly with these
interceptors, but you can both interrogate the interceptor to see its actions, and add and
remove actions too.
Get pipeline
If property interception is enabled for the EntityGroup, which it is by default, then all
appropriate BeforeGet property interceptors are invoked. These property interceptors may
cancel the get altogether.
The default version of the property value is retrieved.
If property interception is enabled, all AfterGet property interceptors are called. These
interceptors may modify the retrieved value (without modifying the backing store), or cancel
the get.
You can use get property interceptors to audit access to properties, to cancel access, and to
modfiy the retrieved value. Don't rely on property interceptors as a robust security
mechanism though.
Set pipeline
If property interception is enabled for the EntityGroup, which it is by default, then all
BeforeSet property interceptors are invoked. These property interceptors may modify the
value, and cancel the set altogether.
BeforeSet verifiers are called. If verifier options specify ShouldExitOnBeforeSetError then the
set does not continue if a validation error occurred.
A check is made for the equality of the old and new values. If equivalent, the property set
does not take place.
The EntityGroup.EntityChanging event is fired. If the change is cancelled further set
processing stops.
The EntityGroup.EntityPropertyChanging event is fired. If the change is cancelled further set
processing stops.
The new value is set in the CurrentValues store for the entity.
The PropertyChanged event is fired.
The EntityGroup.EntityPropertyChanged event is fired.
The EntityGroup.EntityChanged event is fired.
AfterSet verifiers are called.
If property interception is enabled for the EntityGroup, all AfterSet property interceptors are
invoked.
As you can see, there are a number of ways you can fine-tune this process. You'll most
commonly use property interceptors to inspect and possibly modify the value to be set, and
validation to ensure the correctness of the data per your validation rules.
Navigation properties
The NavigationEntityProperty represents either a related entity, called a scalar reference, or a
list of entities, called a list reference.
By default, all navigation properties are lazily loaded. In Silverlight, they're loaded using
asynchronous navigation. Your first get of a property value will cause the related entity or
entities to be lazily loaded into the entity cache.
You can find a full discussion of navigation properties and how they are loaded in the query
topic. Here we'll briefly discuss the get and set pipelines for scalar and list navigation
properties.
Scalar navigation properties
Here's the now familiar generated property:
C#
public Customer Customer {
get { return PropertyMetadata.Customer.GetValue(this); }
set { PropertyMetadata.Customer.SetValue(this, value); }
}
VB
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
... and the corresponding NavigationScalarEntityProperty :
C#
public static readonly IbEm.NavigationScalarEntityProperty<OrderSummary, Customer> Customer
=
new IbEm.NavigationScalarEntityProperty<OrderSummary, Customer>(
"Customer", true, "FK_OrderSummary_Customer", IbEm.QueryDirection.ToRole2);
VB
Public Shared ReadOnly Customer As New IbEm.NavigationScalarEntityProperty(Of
OrderSummary, _
Customer)("Customer", True, "FK_OrderSummary_Customer", IbEm.QueryDirection.ToRole2)
Like a simple property, a NavigationScalarEntityProeprty will have both a GetterInterceptor
and SetterInterceptor. You can inspect and add property interceptor actions to these
interceptors.
Get pipeline
If property interception is enabled for the EntityGroup, which it is by default, then all
appropriate BeforeGet property interceptors are invoked. These property interceptors may
cancel the get altogether.
Determine if a query should be issued:
o If the current FetchStrategy is CacheOnly or the EntityReferenceLoadStrategy is
DoNotLoad, then the current ScalarEntityReference value is returned. This might be a
null entity.
o If the referenced entity has already been loaded it is returned.
o Otherwise either an EntityKeyQuery or EntityRelationQuery is built to retrieve the
related entity. An EntityKeyQuery is used when navigating to a "principal" entity if all
EntityKey values are present.
o The query is executed, synchronously or asynchronously depending on the setting of
UseAsyncNavigation. If synchronous, the retrieved entity is returned from the get; if
asynchronous, a pending entity is returned.
If property interception is enabled all appropriate AfterGet property interceptors are called.


Set pipeline
If property interception is enabled for the EntityGroup, which it is by default, then all
appropriate BeforeSet property interceptors are invoked. These property interceptors may
cancel the set altogether.
BeforeSet verifiers are called. If verifier options specify ShouldExitOnBeforeSetError then the
set does not continue if a validation error occurred.
A check is made for the equality of the old and new values. If equivalent, the property set
does not take place.
The EntityGroup.EntityChanging event is fired. If the change is cancelled further set
processing stops.
The EntityGroup.EntityPropertyChanging event is fired for the corresponding foreign key
property. If the change is cancelled further set processing stops.
The new scalar reference value is set.
The PropertyChanged event is fired for the foreign key property.
The EntityGroup.EntityPropertyChanged event is fired for the foreign key property.
The PropertyChanged event is fired for the navigation property.
The EntityGroup.EntityPropertyChanged event is fired for the navigation property.
The EntityGroup.EntityChanged event is fired.
AfterSet verifiers are called.
If property interception is enabled all appropriate AfterSet property interceptors are called.
The set pipeline for a reference property is more complex than for an ordinary data
property. Because both the navigation property reference and the corresponding foreign key
property are set, there are more opportunities for interception and validation, and more events
are raised. There is actually quite a bit more going on under the hood, such as "fixup" of keys
and attaching of entities, but we won't discuss that here.
List navigation properties
Our generated property:
C#
public IbEm.RelatedEntityList<Order> Orders {
get { return PropertyMetadata.Orders.GetValue(this); }
}
VB
Public ReadOnly Property Orders() As IbEm.RelatedEntityList(Of Order)
Get
Return PropertyMetadata.Orders.GetValue(Me)
End Get
End Property
We see there's no setter with a NavigationListEntityProperty , since you retrieve the list (even
if empty) and add and remove entities to the list.
Here's the NavigationListEntityProperty:
C#
public static readonly IbEm.NavigationListEntityProperty<Customer, Order> Orders =
new IbEm.NavigationListEntityProperty<Customer, Order>(
"Orders", true, "FK_Order_Customer", IbEm.QueryDirection.ToRole1);
VB
Public Shared ReadOnly Orders As New IbEm.NavigationListEntityProperty(Of Customer,
Order)("Orders", _
True, "FK_Order_Customer", IbEm.QueryDirection.ToRole1)
The NavigationListEntityProperty will have only a GetterInterceptor. You can inspect and
add property interceptor actions to this interceptor.
Get pipeline
If property interception is enabled for the EntityGroup, which it is by default, then all
appropriate BeforeGet property interceptors are invoked. These property interceptors may
cancel the get altogether.
Determine if a query should be issued:
o If the current FetchStrategy is CacheOnly or the EntityReferenceLoadStrategy is
DoNotLoad, then the current ListEntityReference values are returned. This might be
an empty list.
o If the referenced list has already been loaded it is returned.
o Otherwise an EntityRelationQuery is built to retrieve the related entities.
o The query is executed, synchronously or asynchronously depending on the setting of
UseAsyncNavigation. If synchronous, the retrieved list of entities is returned from
the get; if asynchronous, a pending entity list is returned.
If property interception is enabled all appropriate AfterGet property interceptors are called.


Add and remove
If a collection is not read only you can add and remove related entities. A RelatedEntityList
will be read only if created from a NavigationListEntityProperty having the
IsCollectionReadOnly flag set, or if the flag has been set directly on the list.
The pipeline for adds and removes is similar to that of a scalar navigation property setter,
since the corresponding scalar setter is what's called under the hood. Many-to-many
navigation properties are the exception, however, since adds and removes in a many-to-many
relationship target relationships instead of entities.
Access entity internals
You access the internals of an entity through the entity's EntityAspect property.
EntityAspect is your gateway to the DevForce infrastructure hidden within each entity. The
EntityAspect tells you whether the entity has changed and how, and allows you to perform
basic functions such as adding and removing the entity from its EntityManager. This topic
covers what you can do with and learn from the EntityAspect.


Hiding entity infrastructure
An entity represents a thing in the application domain. A Customer represents "customer-
ness". You modeled the Customer entity to suit the needs of programmers who write code
about customers. The Customer entity should exhibit "customer-ness". Here is what a
Customer instance looks like in IntelliSense:

Almost all members are Customer-specific. They are data properties, navigation properties,
and custom methods (if we had some).
A few members concern infrastructure having nothing to do with Customer per se. These are
members of the Customer's base classes such as Object.GetHashCode and Object.GetType ...
and Entity.EntityAspect.
They are noise when our attention is on "customer-ness". They can distract us from our
primary purpose - to do business with a customer.
In an ideal world they would be invisible. In practice, we need them. At various times we
have to set aside our "Customer" perspective and see the Customer entity as a .NET object.
Sometimes we need to work with it as Object. Sometimes we need to work with it as an
Entity. When we need to shift our perspective, we need to shift quickly.
The architect's challenge is to keep "customer-ness" on center stage and have "object-ness"
and "entity-ness" quietly ready in the wings.
You have to access the entity internals of Customer from time to time. Rather than clutter
Customer with lots of "entity-ness" members, DevForce wraps them in a single helper object,
the EntityAspect. The EntityAspect property is the place to go for "entity-ness" - the place to
go for access to the inner entity nature of a Customer.
What's in EntityAspect
You'll most often use EntityAspect to determine the state of the entity: is it Added, has it been
changed, is it null or pending? You'll also use EntityAspect to work directly with validation
errors or to access entity metadata. In general, though, you don't often need to work with the
EntityAspect, as DevForce will handle the entity for you as you query, modify and save your
entities.
Learn the state of the entity
Member Purpose
EntityKey The value that uniquely identifies this entity.
EntityState
The state of the entity - whether unchanged, added, modified, deleted or
detached.
HasChanges If changes are pending for this entity.
IsChanged
If changes are pending for this entity, i.e., EntityState is added, modified, or
deleted.
IsNullEntity
If this entity is the special "null entity" ("nullo"). A reference navigation
property returns such a null entity when it can't return the related entity
(rather than return null and risk an exception).
IsPendingEntity
If this entity instance is a placeholder for a real entity of this type. An entity
will be pending when using asynchronous navigation and the retrieval from
the database has not completed.
PendingEntityResolved Raised when a pending entity has been retrieved from the database.
IsNullOrPendingEntity
If this entity is either the null entity or a pending entity. A quick way to tell
if the entity is real and complete.
Change the state of the entity
Other than calling Delete, in most circumstances you won't need to use the methods described
below, as DevForce will automatically handle the state of the entity as it's queried, modified,
and saved.
Member Purpose
Delete
Mark this entity for deletion; the entity will be deleted from the database
when saved.
RejectChanges Undo pending changes.
AcceptChanges
Commit pending changes locally as if the entity were saved and now
unchanged. Beware! Does not update the database. You do not need to call
AcceptChanges during normal save processing, as DevForce will do it for
you when a save completes successfully.
SetAdded
Convert the state of the entity such that it appears to have been newly
created. If saved, DevForce will try to insert it into the database. When you
create a new entity and add it to an EntityManager, it will automatically be
marked as Added and you do not need to call this method.
SetModified
Convert the state of the entity such that it appears to be a modified entity
that came from the database. If saved, DevForce will try to find and update
the corresponding database object. When you modify an entity in cache it
will automatically be marked as Modified by DevForce and you do not need
to call this method.
GetValue
Get the value of the named property. Could get the current value of the
property or one of the other versions.
SetValue Set the current value of the named property.
ForcePropertyChanged Raise the entity's PropertyChanged event on demand.
Learn about the entity's validity
Member Purpose
ValidationErrors
Get a modifiable collection of the currently detected validation errors for
this entity.
VerifierEngine
Get the VerifierEngine used by this entity's auto-validating property setters.
The engine always comes from the entity's EntityManager. It is null if the
entity is detached; for this reason property setters don't validate input
automatically when the entity is detached.
Work with the entity's EntityManager
Member Purpose
EntityManager Get the EntityManager to which the entity is attached. Null if detached.
AddToManager
Add the entity to its associated EntityManager as a new entity. An
EntityManager is associated with an entity when the entity is created with
the CreateEntity method.
RemoveFromManager
Detach the entity from its EntityManager. Removing an entity from its
EntityManager is not the same thing as deleting an entity. The entity will
not be deleted from the back end data source with RemoveFromManager.
FindRelatedEntities Find cached entities related to this entity by a specific link.
GetRelatedEntities
Get entities related to this entity by a specific link; depending on
circumstances and parameters DevForce could retrieve them from the
database (asynchronously in Silverlight).
EntityGroup
Gets the collection of entities to which this entity belongs. When this entity
is attached to an EntityManager, the EntityGroup contains this entity and
every other entity of its type in the cache. EntityGroup events reveal when
entities in the group are added, removed, or changed.
Get Metadata about the entity
Member Purpose
EntityMetadata Get model metadata about this entity's type.
GetProperty
Get an EntityProperty metadata object by name with which you can inspect
or modify property values generically.
GetDataProperty
Get a data meta-property by name which you can inspect or use to get and
set values generically.
GetNavigationProperty
Get navigation meta-property by name which you can inspect or use to add
and remove related entities generically.
EntityAspect's own stuff
Member Purpose
Entity A back-reference to get the entity for which this is the EntityAspect.
Wrapper
A back-reference to the EntityWrapper for which this is the EntityAspect.
For a DevForce generated entity the Entity and Wrapper properties return
the same entity object because the entity inherits from both Entity and
EntityWrapper. The distinction between Entity and EntityWrapper is
relevant only for POCOs.
PropertyChanged
Raised by EntityAspect when certain of its own properties change such as
EntityState, EntityKey, and HasChanges. Not to be confused with
PropertyChanged event for the entity.
Check for changes
An entity's EntityState tells you if it is attached to an EntityManager, if it has pending
(unsaved) changes, whether it was newly created, previously existing, or scheduled for
deletion. This topic covers what these states mean, how they change, and some ways to
program with EntityState.


Has it changed?
No direct property of Customer can tell you if a particular Customer instance has been
changed. That's not a question about "Customer-ness"; it's an entity infrastructure question.
You access a Customer object's entity internals by means of its EntityAspect property.
EntityAspect opens the door to a wealth of information about your entity.
Three EntityAspect members can tell you if the entity has changed:
HasChanges
IsChanged
EntityState
HasChanges() and IsChanged are synonyms. One is a method; the other is a property to
which you can data bind. IsChanged delegates to HasChanges(). Use either like this
C# if (aCustomer.EntityAspect.IsChanged) // do something
VB If (aCustomer.EntityAspect.IsChanged) Then ' do something
HasChanges() is defined in terms of the EntityState. It reports that the entity has changes if
the entity's EntityState is any value other than Unchanged.

A thought for later: IsChanged is always true for a Detached entity whether or not it actually
had changes before it was detached. In other words, don't use HasChanges() and IsChanged
with detached entities.
HasChanges() and IsChanged are syntactic sugar wrapped around the property that really
matter, the EntityState
Introduction to EntityState
EntityState addresses these three questions:
Is the entity attached to an EntityManager or is it detached?
Is the entity changed or not
If changed, is it an added entity, a modified entity, or an entity marked for deletion?
The answer is one of the IdeaBlade.EntityModel.EntityState enums returned by the
EntityAspect.EntityState property.
C# currentState = aCustomer.EntityAspect.EntityState; // an EntityState enum
VB currentState = aCustomer.EntityAspect.EntityState ' an EntityState enum
The currentState will be one of these EntityState enums :
EntityState Summary
Detached
The entity is not attached to an EntityManager. It is in this state upon creation or after
being removed from an EntityManager.
Unchanged
The entity is attached to the EntityManager, presumed to exist in the database, and has
not changed since last queried or saved.
Added
The entity has been added to the EntityManager and is presumed to be new (not in the
database).
Modified
The entity is attached to the EntityManager, presumed to exist in the database, and has
been modified since last queried or saved.
Deleted The entity was deleted using the Entity.Delete() method.
In this topic we discuss what the states mean and how to use them. A separate topic covers the
operations that changea an entity's EntityState.
The Detached EntityState
You usually work with an entity that is attached to an EntityManager. An attached entity is
an entity that is in an EntityManager's entity cache. You can ask it for its EntityManager:
C# manager = aCustomer.EntityAspect.EntityManager;
VB manager = aCustomer.EntityAspect.EntityManager
The variable manager has a value if the entity is attached; is is null if the entity is not
attached.
It's easier to check the EntityState than to test for a null EntityManager.

An entity is attached if its EntityState is not Detached.
C# if (aCustomer.EntityAspect.EntityState != EntityState.Detached) // it's attached
VB If (aCustomer.EntityAspect.EntityState <> EntityState.Detached) Then ' it's attached
There are reasons to work with a detached entity and certain operations automatically detach
an entity. Another topic covers attaching and detaching entities in more detail. Here we
discuss some of the implications of being attached or detached.
Certain infrastructural features only work when the entity is attached. For example, you can
only get to the database via a navigation property when the entity is attached.
Consider the following statement:
C# aCustomer = anOrder.Customer; // get the Order's parent Customer
VB aCustomer = anOrder.Customer ' get the Order's parent Customer
The property behaves differently for attached and detached entities.
If anOrder is attached, its aCustomer is either a real Customer entity or the special form of a
Customer entity called "the null entity" (aka "the nullo") depending upon whether anOrder
has a customer or not. If DevForce isn't sure, it could query the database for the parent
Customer.
You can check if the Order's Customer is real or the nullo.
C# if (aCustomer.EntityAspect.IsNullEntity) // ...
VB If (aCustomer.EntityAspect.IsNullEntity) Then ' ...
If anOrder is detached, aCustomer is probably null. The anOrder object doesn't have an
EntityManager so it can't find its parent Customer in cache and it has no way query the
database. It might have a Customer, left over from its former life as an attached entity. But it
probably doesn't.
That means that the example above would throw a NullReferenceException.
Don't expect automatic validation when you set a property of a Detached entity. Automatic
property validation depends upon access to the EntityAspect.VerifierEngine. The
VerifierEngine is null for a Detached so the data property skips the validation step.
Make sure you know when you're working with a Detached entity.
Use combo-EntityStates to find entities in cache
EntityState is defined as a flag enum which means individual enum values can be OR'd
together to represent a combination of states.
C#

addedOrModified = EntityState.Added | EntityState.Modified;
VB addedOrModified = EntityState.Added Or EntityState.Modified
The EntityState enum includes two particularly useful combinations:
EntityState Summary
AnyAddedModifiedOrDeleted Added or Modified or Deleted.
AllButDetached All states except detached.
You can use these combo enums to select entities from the cache.
C#
// All entities in cache with pending changes
changedEntities = manager.FindEntities(EntityState.AnyAddedModifiedOrDeleted);

// All Customer entities in cache
custsInCache = manager.FindEntities<Customer>(AllButDetached);
VB
' All entities in cache with pending changes
changedEntities = manager.FindEntities(EntityState.AnyAddedModifiedOrDeleted)

' All Customer entities in cache
custsInCache = manager.FindEntities(Of Customer)(AllButDetached)
Simplify EntityState checking with extension methods
You frequently ask if an entity is in a particular state or one of a common set of states. The
code to get the answer is not difficult but it is tedious.
C#
currentState = aCustomer.EntityAspect.EntityState;

if (EntityState.Deleted == currentState) // ...
if ((currentState & (EntityState.Added | EntityState.Modified)) > 0) // ...
VB
currentState = aCustomer.EntityAspect.EntityState

If (EntityState.Deleted = currentState) Then ' ...
If ((currentState And (EntityState.Added Or EntityState.Modified)) > 0) Then ' ...
These boolean EntityState extension methods make it easier to check for specific states and
combination.
IsDetached()
IsModified()
IsDeleted()
IsUnchanged()
IsAddedOrModified()
IsAddedOrModifiedOrDeleted()
IsDeletedOrDetached()
IsDeletedOrModified()
Here are the same state-checking statements as above, rewritten with extension methods.
C#
currentState = aCustomer.EntityAspect.EntityState;

if (currentState.IsDeleted()) // ...
if ((currentState.IsAddedOrModified()) // ...
VB
currentState = aCustomer.EntityAspect.EntityState

If currentState.IsDeleted() Then '...
If (currentState.IsAddedOrModified() Then '...





Change the EntityState
is topic identifies many of the things you can do to an entity that change its EntityState.


Operations that change the EntityState
Here's a brief summary of the EntityState-changers you'll run into most frequently:
Operation Summary
Query
A successful query returns entities that are attached to the EntityManager. A
newly-queried entity is Unchanged unless it happens to already be in cache. If
the entity is already in cache, it retains its current EntityState by default. See
the MergeStrategy topic for details.
AddEntity
Attaches the entity to the EntityManager as an Added entity. The entity is
presumed to be new and unknown to the database. It would be inserted if
saved.
AddToManager()
Attaches the entity to an inner, hidden EntityManager as a new entity. Call
for an entity you created with EntityManager.CreateEntity(). See the special
topic on this method.
AttachEntity
Attaches the entity to the EntityManager as an Unchanged entity. The entity
is presumed to be in the database already.
RemoveFromManager
Detaches the entity from its current EntityManager. The new state is
Detached.
Set a property
An Unchanged entity becomes Modified. Entities in other states retain their
EntityState values.
Save
If the save succeeds, Added and Modified entities become Unchanged.
Deleted entities are removed from cache and become Detached
RejectChanges
Modified and Deleted entities are rolled back to their pre-change values; their
new EntityState is Unchanged. Added entities are removed from the
EntityCache and become Detached.
AcceptChanges
As with save, Added and Modified entities become Unchanged. Deleted
entities are removed from cache and become Detached. Save actually calls
AcceptChanges. Beware: calling AcceptChanges does not save them. Call it
with a good reason, e.g., building test and design-time entities.
SetAdded
Change the entity from its current, non-Detached, state to the Added state. A
feature most useful when building test and design-time entities.
SetModified
Change the entity from its current, non-Detached, state to the Modified state.
A feature most useful when building test and design-time entities.
Listen for changes
Listen for changes to specific entities or for changes to groups of entities in cache by
attaching handlers to Entity and EntityManager events.


EntityManager events

The EntityManager has a number of events that provide access to a variety of information
regarding changes to both the Entities within an EntityManager as well as the
Instance events:
Event Description
Cleared Fired whenever the EntityManager.Clear method is called.
EntityChanging
Fired just before any entity within the EntityManager is about to be changed. The
change can be cancelled from within the event handler. Information about the
change is available via an EntityChangingEventArgs parameter passed to the event
handler.
EntityChanged
Fired just after any entity within the EntityManager is changed. Information about
the change is available via an EntityChangedEventArgs parameter passed to the
event handler.
EntityServerError
Fired when an error occurs during an operation that passed data to the
EntityServer. The IdeaBlade.EntityModel allows the exception to be examined and
optionally "handled" so that the exception does not propogate further. This can be
used as a "last resort" error handler for any EntityServer errors.
Querying Discussed here
Fetching Discussed here
Queried Discussed here
Saving Discussed here
Saved Discussed here
Both the EntityChanging and EntityChanged event handlers are passed an event args variable
that in turn contains an instance of the EntityAction enumeration. This action may be used to
determine the kind of change that is either about to occur or has just occured. The descriptions
below are phrased in the past tense but should be translated to the future tense in the case of
the EntityChanging event. EntityAction is a flag enumeration meaning that more than one
action may set at the same time. Where this occurs, it is called out.
EntityAction Description
Remove
The entity has been removed. Either via a call to RemoveEntity or after
the save of a Deleted entity.
Change
The entity has changed as a result of a change to some property on the
entity.
Rollback
The most recent change to the entity has been rolled back. This occurs as
a result of a RejectChanges call.
Commit
The changes to the entity have been committed. This occurs as a result
of a AcceptChanges call.
Add The entity has just been attached to the EntityManager.
ChangeOriginal
The original version of the entity has been changed. This occurs as a
result of a Merge operation (via Query or ImportEntities) with
PreserveChangesUpdateOriginal strategy.
ChangeCurrentAndOriginal
The original and the current versions of the entity have been changed.
This occurs on any Merge operation other than the one above.
AddOnQuery
The entity has been attached as a result of an query operation. (This is
also an Add EntityAction)
AddOnImport
The entity has been attached as a result of an import operation. (This is
also an Add EntityAction)
AddOnAttach
The entity has been attached to as a result of an AttachEntity call but
with an EntityState other than Added. (This is also an Add EntityAction)
Delete The entity was marked for deletion
Static ( class level) events:
Event Description
EntityManagerCreated A class level event that is fired anytime a new EntityManager is created
EntityGroup events
In DevForce, every EntityManager contains a collection of EntityGroups. Each EntityGroup
in turn contains all of the entities of a single entity type that are part of this EntityManager.
An EntityGroup can be retrieved via either of the following methods on an EntityManager.
C#
public EntityGroup GetEntityGroup(Type entityType);
public EntityGroup<T> GetEntityGroup<T>();
VB
Public Overloads Function GetEntityGroup( _
ByVal entityType As Type _
) As EntityGroup
Public Overloads Function GetEntityGroup(Of T)() As EntityGroup(Of T)
Each EntityGroup has a number of events that may be handled:
Event Description
EntityPropertyChanging
Fired just before a property of an entity changes. The associated
EntityPropertyChangingEventArgs contains information regarding the entity
being changed, the property being changed and the "proposed value" for
the change. The change may be cancelled, in which case the property set
operation will not occur.
EntityPropertyChanged
Fired just after a property of an entity changes. The associated
EntityPropertyChangedEventArgs contains information regarding the entity
that was changed, the property that was changed and the "value" for the
change.
EntityChanging
This is basically the same as the EntityManager.EntityChanging event simply
fired at a different level.
EntityChanged
This is basically the same as the EntityManager.EntityChanged event simply
fired at a different level.
There may be cases where a developer wants to suppress all "change notification" within an
EntityGroup for a period of time. This can be accomplished by setting the ChangeNotificationEnabled
property to 'false'. Note that this will effect change notification at the EntityManager level
(EntityChanging, EntityChanged) as well as at the Entity level (INotifyPropertyChanged).
Entity events
Event Description
PropertyChanged Implementation of INotifyPropertyChanged
ErrorsChanged Explicit implementation of INotifyDataErrorInfo
EntityAspect events
Most changes that relate to an Entity are handled by the events listed previously on this page.
However, there are a small number of properties that are only available thru the EntityAspect
of an entity. These are properties like EntityState and EntityKey and there is a seperate
INotifyPropertyChanged implementation on the EntityAspect to handle notification of
changes to these properties.
Event Description
PropertyChanged
Part of INotifyPropertyChanged implementation. Properties on the EntityAspect
that are subject to changed and therefore available via the PropertyChanged
notification are EntityState, EntityKey, IsChanged, and HasErrors.
Undo changes
Undo pending (unsaved) changes to a single entities, selected entities, or all entities in cache
by calling one of the RejectChanges methods. In addition, DevForce entities also support the
IEditableObject interface which allows for the undo of changes within an "editing" context"


The RejectChanges method
An application can undo changes made to individual entity via the
EntityAspect.RejectChanges method. The same operation can be performed against all of the
relevent entities within an EntityManager ( all modified, deleted, or added entities) via the
EntityManager.RejectChanges method.
This is a single level undo. Undoing a pre-existing object, whether added, modified or marked
for deletion, restores it to its state when last retrieved from the data source;
The following table describes what happens to an entity in any given state when a
RejectChanges call is made on it.
Original
EntityState
EntityState
After
Other side effects
RejectChanges
Modified Unchanged Original values become current values
Added Detached
Entity gets removed from the cache ( as if it had never been
Added).
Deleted Unchanged Entity gets "undeleted"
Unchanged Unchanged Nothing actually happens here.
Detached Detached Nothing actually happens here.
There is no undo of an undo.
DevForce Entities also implement the .NET I EditableObject interface. This interface provides
for a second form of undo that is commonly utilized by UI controls when binding directly to
an entity. By convention this interface is implemented explicitly and therefore requires
casting.
Access to "Undo" information
DevForce effectively maintains a copy of each entities "original" version. When you access
the properties of an entity, either via a get or set operation, you are accessing the "default"
version of the entity. The property values of the "original", as well as a "proposed" version
when inside of an IEditableObject edit session, however, are available as well. The values for
any data property of an object are available via either of the following two overloads of the
EntityAspect.GetValuemethod. This is discussed in more detail here.
C#
public Object GetValue(String propertyName, EntityVersion version);
public Object GetValue(DataEntityProperty dataEntityProperty, EntityVersion version);
VB
Public Function GetValue(ByVal propertyName As String, ByVal version As EntityVersion) As
Object
End Function
Public Function GetValue(ByVal dataEntityProperty As DataEntityProperty, ByVal version As
EntityVersion) As Object
End Function
This value returned from the original version is usually exactly what was queried from the
database, although it is possible to update the "original" to match the "current" version via
either the EntityAspect.AcceptChanges or EntityManager.AcceptChanges method calls.
EntityVersion is an enumeration that with the following values:
Value Description
Default
The default version for the state of the entity. This is a version that is used to actually
reference another version based on the state of the entity. A version of Default will almost
always mean Current with the two exceptions being
when an object is within an IEditableObject session, the default version is
Proposed.
when an object has an EntityState of Deleted, its default version is Original.
Original
The original version of the entity from when it was last queried, saved or had
AcceptChanges called on it.
Current The most recent version of the entity, outside of an IEditableObject session.
Proposed The value of the entity when within an IEditableObject session.
Undo of a change to a navigation property that returns a list

The RejectChanges method basically returns an entity to the state it was in when it was last
queried or saved. If other related objects are associated with this entity by being added to or
removed from a "list" navigation property then the RejectChanges call will not have any
effect on the collection returned by the property. This is because information about what
entities are associated with another entity is not considered part of the persistent state of the
entity except in the case where a foreign key reference id exists ( or in case of a many-many
relationship). Since most relationships do have a foreign key defined on one side or the other
of the relationship it is often sufficient to call RejectChanges on the entities on both sides of a
relationship in order to restore the "graph" to an earlier state.
Another approach is to use the rollback mechanism described under the "Snapshot changes"
topic.
Add, attach, and remove
This topic covers how to add new entities to an EntityManager's cache, how to remove
entities from the cache, and how to attach other entities to the cache such that they appear to
have been queried rather than created.


When do entities get attached?
In order for entities to be managed by DevForce they must first be associated with an
entitymanager. Entities will be associated with an EntityManager as a result of any of the
following operations:
A query.
A navigation from one entity to another that in turn triggers a query.
The creation of a new entity and its addition to an EntityManager.
An entity can only be associated with a single EntityManager at one time. Every entity has an
associated EntityState that indicates whether a particular entity is new, modified, marked for
deletion, or unmodified. The EntityState for an entity is automatically set and updated by the
DevForce infrastructure.
Attaching entities to the EntityManager
Once an entity has been created, it must be attached to an entitymanager before it can be
saved, validated, or participate in a number of other services that the EntityManager class
offers. Entities may be added to the EntityManager in two ways; either via the EntityManager
EntityManager.AddEntity method or via the EntityManager EntityManager.AttachEntity
method. The AttachEntity method is actually the primary workhorse here and the AddEntity
method actually delegates to it. The difference between these two methods is that the
AddEntity method adds the entity to an EntityManager in an "Added" state, whereas
AttachEntity can add an entity to an EntityManager in any of the following EntityStates,
"Unchanged", "Added" or "Modified". The AttachEntity method, by default, attaches entities
in an "Unchanged" state, but the method offers an optional parameter that allows you to
specify the desired resulting EntityState.
The AddEntities and AttachEntities methods perform the same operations as described above
but support the ability to attach collections of entities in a single call.
So why would we want to attach entities in different states?
EntityState Use case

Added
Probably the most common case. Usually used after creating a new entity that we want
to have inserted into the database on the next save. This is such a common case that
the AddEntity method was created just to cover this case. Any time an entity is attached
in this state DevForce also performs the task of generating and updating the entity with
a 'temporary' primary key if the entity has been declared as participating in automatic id
generation.

Unchanged
Less common case. Usually used when reattaching a previously detached entity and we
don't want any persistence operation to occur on the entity.

Modified
Less comon case. Usually used when reattaching a previously detached entity and we
want to be able to update the backend database with the values of this entity. Note
that an entity that is attached in a modified state will preserve any of its "original
values" for the purposes of determining which properties actually require modification
on the database. These original values will not exist unless the entity was previously
queried or saved and then detached.

In addition to the EntityManager.AddEntity method mentioned above, the
EntityAspect.AddToManager method does exactly the same thing. The AddToManager
method is provided because it is sometimes clearer, within an entity constructor to write code
where the entity adds itself to a manager, instead of the reverse.
Attaching entity graphs
An entity graph is group of entities that are associated with one another via navigation
properties. It is possible to 'wire up' a graph of entities before any of them have been attached
to an EntityManager. When any one of these entities is then attached, all of the entities in the
group will be attached as well, in whatever state was specified for the initial entity.
In addition, if we ever use a navigation property on an already attached entity to reference a
detached entity, the detached entity will automatically get attache, along with any of its
detached relations. In this case the detached entities will all be attached in an added state.
Detaching entities
Entities can be removed from an EntityManager in either of the following two ways:
EntityManager.RemoveEntity or EntityManager.RemoveEntities*
EntityAspect.RemoveFromManager
Note that 'removing' or 'detaching' an entity from the EntityManager is NOT the same as
deleting it. Removing an entity from an EntityManager marks the entity as 'detached'.
Detaching is basically telling the EntityManager to 'forget' the entity.
Note that any dependent children of this entity will NOT be removed, they will be
"orphaned", meaning that they will no longer have a parent but will still exist in the
EntityManager.
Deleting, a completely different operation, marks the entity as 'deleted' and schedules it for
deletion during the next save operation at which point it will be removed from both the
database and the EntityManager.
Detached entities can be reassociated with an EntityManager via either the AddEntity or
AttachEntity methods described earlier.
There is one other issue related to removing or detaching entities from an EntityManager. It
has to do with the state of the EntityManager's query cache after the removal of an
entity. Because DevForce cannot associate a removal of an entity with the query or queries
that produced it, by default, DevForce is forced to clear its query cache ( not the entity cache)
when a removal occurs. This may seem drastic, but basically the query cache is there to
improve performance when DevForce knows that a query has already been processed and that
it can return the same results running from cache as it would when querying from a
database. When any entity is removed from the cache, DevForce loses the ability to make this
guarantee. This is the default behavior, but you can tell DevForce not to clear the query cache
by making use of the optional second parameter of the
RemoveEntity/RemoveEntities/RemoveFromManager methods.
Note that the removall of Added entities will not trigger the default clearing of the query cache
because these entities could never have been returned from a query.
Using the AttachEntity method for testing
Those of you who write tests and don't want those tests to touch the database will appreciate
the ability of the AttachEntity method to be used in testing.
As you know, you sometimes need to write tests which rely upon interaction with the
EntityManager. You want to populate a disconnected EntityManager with a small collection
of hand-rolled stub entities. While such tests are integration tests because they rely on a
dependency, we still want to make them easy to write and we want them to be fast. That
means we don't want a trip to a database when we run them; we shouldn't need to have a
database to run them.
I usually start by creating a test-oriented, disconnected EntityManager ... which can be as
simple as the following:
C# var testManager = new EntityManager(false /* disconnected */ );
VB Dim testManager = New EntityManager(False) ' disconnected
The easiest way to get a stub entity is to "new" it up, set some of its properties, give it an
EntityKey, and dump it in our testManager. When we're done it should appear there as an
unchanged entity ... as if you had read it from the datastore.
The catch lies in the answer to this question: "How do I add the entity to the manager?"
In the absence of AttachEntity() method, you would have to use EntityManager.AddEntity().
But after AddEntity, the EntityState of the entity is always "Added". You want a state of
"Unchanged" so you have to remember to call AcceptChanges (which changes the state to
"Unchanged").
That's not too hard. Unfortunately, it gets messy if the key of the entity is auto-generated (e.g.,
mapped to a table whose id field is auto-increment) because DevForce automatically replaces
your key with a temporary one as part of its auto-id-generation behavior.
We could explain how to work around this, but the AttachEntity() method already does what
we need.
Let us elaborate here and compare it to some similar methods by calling out some facts about
the following code fragment:
C# theEntityManager.AttachEntity(theEntity);
VB theEntityManager.AttachEntity(theEntity)
theEntitys EntityKey (the key) must be preset prior to the attach operation (which will not
touch the key).
An exception is thrown if an entity with that key is already in the cache.
After attach, theEntity is in an Unchanged EntityState (the state).
theEntity is presumed to exist in the persistent store; a subsequent change and save will
translate to an update statement.
After a successful attach, a reference to theEntity is a reference to the entity with that key in
the managers EntityCache. Contrast this with the effect of anEntityManager.Imports(new []
,anEntity-) as discussed below.
theEntity must be in the Detached state prior to the operation.
An exception is thrown if theEntity is other than in Detached state prior to the operation.
After attach, related entities are implicitly associated with theEntity automatically; for
example, if anOrder with Id==22 is attached and there are OrderDetails with parent
OrderId==22, then after the attach, anOrder.OrderDetails returns these details and any one
of them will return anOrder in response to anOrderDetail.Order.
The sequence of attachments is not important; OrderDetails may be added prior to the
parent Order.
Attach has no effect on theEntityManagers QueryCache.
AddEntity behaves the same way as AttachEntity except as follows:
After add, theEntity is in an Added state
theEntity is presumed to be new and to be absent from in the persistent store; a save will
translate to an insert statement.
If the key for this type is auto-generated (e.g., backed by an auto-increment field in the
database), the existing key will be set to a generated temporary key, replacing the prior key
value.
The following is true regarding detaching anEntity:
After detach, anEntity enters the Detached state no matter what its prior state.
Detaching an Order does not detach its child OrderDetails - they remain orphaned in the
cache.
The sequence of detachments is not important; an Order may be detached prior to detaching
its child OrderDetails.
Detach has no effect on theEntityManagers QueryCache.
Difference between AttachEntities and ImportEntities
EntityManager.ImportEntities is another way of populating an EntityManager with a
collection of entities that may have come from anywhere (including hand-rolled). Here's how
you might "import" a single stub entity:
C# theEntityManager.ImportEntities(new [] {theEntity});
VB theEntityManager.ImportEntities( {theEntity})
ImportEntities differs from AttachEntity in that:
It requires a MergeStrategy to tell it what to do if an entity with the same key as "theEntity"
already exists in the cache.
It merges "theEntity" into the cache based on the MergeStrategy
It makes a clone of "theEntity" and adds that clone to the EntityCache ... unless "theEntity"
happens to already be in the cache in which case it is ignored ... which means that
Using our example and assuming that "theEntity" was not already in the manager, the entity
instance in the cache is not the same as the entity instance you imported, although their keys
are equal; the following is true:


theEntity |= theManager.FindEntity(theEntity.EntityAspect.EntityKey)
A "clone" is a copy of an entity, equivalent to calling the following:
C# ((ICloneable)theEntity).Clone();
VB CType(theEntity, ICloneable).Clone()
This is a copy of the entity, not of its related entities.
Creating a "live" filtered list of entities
The IdeaBlade.EntityModel.EntityListManager<T> class is intended to provide 'live-list"
management capabilities to any list containing DevForce entities. The idea of a "live" or
"managed" list is that the membership to the list is kept continuously updated based on
changes to entities in an EntityManager's entity cache. Filter expressions are used to
determine the rules by which an entity is either included in or excluded from a specific list.


Creating an EntityListManager

Consider the following code:
C#
Predicate<Employee> filter = (emp) => emp.City == "London";
_employeeEntityListManager = new EntityListManager<Employee>(_em1, filter, null);
bool refreshListWhenPlacedUnderManagement = true;
_employeeEntityListManager.ManageList(_salesReps,
refreshListWhenPlacedUnderManagement);
V
B
Dim filter = New Predicate(Of Employee)(Function( _
anEmployee As Employee) anEmployee.City = "London")
_employeeEntityListManager = New EntityListManager(Of Employee)(_em1, filter, Nothing)
Dim refreshListWhenPlacedUnderManagement As Boolean = True
_employeeEntityListManager.ManageList(_salesReps, refreshListWhenPlacedUnderManagement
)
This code sets up an EntityListManager to watch the cache for changes to Employees, or the
insertion of new Employees. If any changed or new Employee is found to be based in
London, a reference to that Employee will be added to the _salesReps list. If any Employee
that was located in London is moved to another city, that entity will be removed from the list.
The second parameter to the ManageList call above, indicates whether you want the
_employeeEntityListManager to clear the list and then scan the current "entity cache" and
repopulate it based on the specified filter. A 'false' value would indicate that you want the list
to be monitored from here on, but that you are confident of its initial population.
The only requirements for the list being managed, in this case: _salesReps, are that it
implement System.Collections.IList; and
contain instances of IdeaBlade.EntityModel.Entity.
A single EntityListManager can manage as many different lists as you wish. To put
_employeeEntityListManager in charge of additional lists, you would simply invoke its
ManageList method again for each desired list:
C#
_employeeEntityListManager.ManageList(_telecommuters, false);
_employeeEntityListManager.ManageList(_fieldAgents, false);
VB
_employeeEntityListManager.ManageList(_telecommuters, False)
_employeeEntityListManager.ManageList(_fieldAgents, False)
Of course, it only makes sense to do this when the same inclusion criteria apply to each
targeted list.
Note that the EntityListManager is NOT 'watching' the list itself, it is only watching the
EntityManager associated with the list and will insure that any changes to any entities within
the EntityManager result is the addition or removal of entities from the list based on the
specified filter.
This means that any changes that are made to the list directly do not result in any filtering action.
So as a general rule, you should usually avoid modifying a 'managed' list directly, and instead
rely on its ability to stay synchronized with its associated EntityManager. The reason that the
list does not 'watch' for changes to itself is that the IList interface does not provide any
eventing mechanism that would allow an external component, such as the EntityListManager,
to perform such a 'watch'. While some implementations of IList do offer such eventing we did
not want to restrict the use of the EntityListManager working only with such lists.
EntityListManagers and the NullEntity
One exception to the general rule described above occurs when you want to add a NullEntity
to a "managed" list. NullEntities are a special form of "detached" entities and do not reside in
the cache, so there is no way that an EntityListManager will ever find one to either add to or
be removed from a managed list. If you want a NullEntity in a managed list, you should
manually add it. The ListManager will not remove it.
EntityListManagers and duplicates
The EntityListManager will not eliminate duplicates from a list. It will, however, insure that it
does not add the same entity more than once. For example, suppose you direct the following
statement against a list, _salesReps, that is already being managed to include Employees
based in London:
C# _salesReps.AddRange(_entityManager.Employees.Where(e=>e.City == "London"));
VB _salesReps.AddRange(_entityManager.Employees.Where(e=>e.City == "London"))
You will end up with duplicate references to each of the London employees! Again, the
general rule is that if you have a managed list, it is best not to attempt to populate it directly.
Allow the EntityListManager to handle the work.
EntityListManagers and performance
EntityListManagers do create a certain amount of overhead, so be judicious in their use. It is
also possible to narrow their scope of what they must monitor more than we did in our
examples above. We instantiated our EntityListManager as follows:
C#
var filter = new Predicate<Employee>(
delegate(Employee anEmployee) { return anEmployee.City == "London"; });
EntityListManager<Employee> employeeEntityListManager =
new EntityListManager<Employee>(_em1, filter, null);
VB
Dim filter = New Predicate(Of Employee)(Function(anEmployee _
As Employee) anEmployee.City = "London")
Dim employeeEntityListManager As New EntityListManager( _
Of Employee)(_em1, Filter, Nothing)
The third argument, which we left null, is an array of EntityProperty objects. By leaving it
null, we told the manager to submit any added or modified Employee to the test encoded in
the filter Predicate. Suppose that, instead, we pass a list of properties of the Employee to this
argument:
C#
EntityListManager<Employee> employeeEntityListManager =
new EntityListManager<Employee>(_entityManager, filter,
new EntityProperty[] { Employee.CityEntityProperty });
VB
Dim employeeEntityListManager As New EntityListManager( _
Of Employee)(_em1, filter, New EntityProperty() {Employee.CityEntityProperty})
Now the EntityListManager will apply its test (about City being equal to London) only to an
Employee whose City property, specifically, was modified. If you simply change only the
Birthdate of an Employee already in the cache, the rule will not be evaluated. It can, after all,
be safely assumed that said Employee would already be in the lists being managed if the
value in its City property were London.
Coding more involved rules
In some of the examples above we passed an anonymous delegate to the constructor of the
Predicate filter. Thats great for simple rules, but you can declare the predicate separately if
you need to do something more involved. This also gives you a chance to name the rule,
which can make your code more readable. Heres a simple example:
C#
private void SetUpEntityListManagerWithNamedDelegate() {
// Identify Customer currently being edited by some process;
// this is a stand-in.
_currentCustomer = _em1.Customers.FirstOrNullEntity();
EntityListManager<Order> orderEntityListManager =
new EntityListManager<Order>(_em1, FilterOrdersByDate,
new EntityProperty[] {
Order.PropertyMetadata.OrderDate,
Order.PropertyMetadata.Customer }
);
}

/// <summary>
/// This rule gets the 1996 Orders for the current Customer
/// </summary>
/// <param name="pOrder"></param>
/// <returns></returns>
Boolean FilterOrdersByDate(Order pOrder) {
return (pOrder.OrderDate.Value.Year == 1996 &&
pOrder.Customer == _currentCustomer);
}
VB
Private Sub SetUpEntityListManagerWithNamedDelegate()
' Identify Customer currently being edited by some process;
' this is a stand-in.
_currentCustomer = _em1.Customers.FirstOrNullEntity()

Dim orderEntityListManager As New EntityListManager(Of Order)(_em1, _
AddressOf FilterOrdersByDate, New EntityProperty() { _
Order.PropertyMetadata.OrderDate, Order.PropertyMetadata.Customer})
End Sub

''' <summary>
''' This rule gets the 1996 Orders for the current Customer
''' </summary>
''' <param name="pOrder"></param>
''' <returns></returns>
Private Function FilterOrdersByDate(ByVal pOrder As Order) As Boolean
Return (pOrder.OrderDate.Value.Year = _
1996 AndAlso pOrder.Customer.Equals(_currentCustomer))
End Function

Import entities
Occasionally, you may have a secondary workflow or editing context that needs to be isolated
from the primary workflow. Creating another EntityManager and importing entities is a
great way to create a "sandbox" environment that copies and isolates changes to the entities
until you are ready to merge them back into the primary workflow.
The secondary EntityManager likely needs to be seeded with entities from the primary
EntityManager. If they have already been cached, this avoids having to go back to the
datasource to retrieve them, but more importantly, some of the entities may be modified and
you want their modified state to be copied into the secondary manager.
Import entities into an EntityManager
To import entities into another EntityManager call ImportEntities.
C# manager.ImportEntities(entities, MergeStrategy.PreserveChanges);
VB manager.ImportEntities(entities, MergeStrategy.PreserveChanges)
This creates a copy of the entities into the cache of the EntityManager. Any changes to the
copied entities in this cache will not affect the source entities. Notice that the second
parameter of ImportEntities takes a MergeStrategy. This MergeStrategy determines how the
entities are merged if they already exist in the target EntityManager's cache.
If you are importing entities into an empty EntityManager, then you don't need to worry about
merge conflicts. This only occurs when you are merging into an EntityManager which may
have potentially modified versions of the same entities. For an in depth discussion about
merging entities see Merge query results into the entity cache.
Work with multiple EntityManagers
Remember that when working with multiple EntityManagers that each one is a separate
editing context and that you may (and probably will) have multiple copies of the same entities
(entities that have the same ID or primary key).
When you are binding the entities to the UI, make sure you understand which instance of the
entity you are binding to. Be very clear about which EntityManager you are using to initialize
a view, and avoid mixing entities from different EntityManagers in the same view.
To learn more about working with multiple EntityManagers see Multiple EntityManagers.
Find entities to import
If you don't have an easy reference to all the entities you want to import, FindEntityGraph can
be of great assistance. FindEntityGraph starts with a set of root entities and retrieves all
related entities for the specified associations (EntitySpans ).
FindEntityGraph does not query the datasource, so make sure that you already have the entities in
cache by using the Include operator in the original query.
C#
var rootEntities = new List<Entity>();
rootEntities.Add(someEmployees);

var spans = new List<EntitySpan>();

EntitySpan span = new EntitySpan(typeof(Employee),
EntityRelations.FK_Order_Employee,
EntityRelations.FK_OrderDetail_Order,
EntityRelations.FK_OrderDetail_Product);

spans.Add(span);

var entityGraph = manager.FindEntityGraph(rootEntities, spans, EntityState.AllButDetached);
VB
Dim rootEntities = New List(Of Entity)()
rootEntities.Add(someEmployees)

Dim spans = New List(Of EntitySpan)()

Dim span As New EntitySpan(GetType(Employee), _
EntityRelations.FK_Order_Employee, _
EntityRelations.FK_OrderDetail_Order, _
EntityRelations.FK_OrderDetail_Product)

spans.Add(span)

Dim entityGraph = manager.FindEntityGraph(rootEntities, spans, EntityState.AllButDetached)
Temporary id remapping
During an import, any entities with a temporary id will be assigned a new temporary id to
avoid conflicts with temporary ids that already exist in the cache. All foreign key references
will also be remapped, so that object navigation will continue to work. Generally, you do not
need to worry about this, but if you are inspecting the temp ids, this is why they change after
import.
Inspect original values
You can inspect the original version of a data property value even if the entity is in a
modified or deleted state.
Normally when you read an entity data property, DevForce returns the "current" value.
Internally DevForce maintains several versions of each data property's value: the current
version (with a pending change if any), its original version (the value as it was when the entity
was last retrieved or saved), and a proposed version (for a change that is no yet recorded).
This topic covers the EntityVersion enumeration and how you use it in combination with the
GetValuemethod to inspect specific versions of property data.


Data Property Versioning
When you undo changes you've made to a modified entity, DevForce reverts the entity's data
properties to their "original" values.
DevForce maintains more than one value per data property. In fact, it may hold up to three
versions of the property value : the current, the original, and a proposed version.
The Current version is the one you see most of the time. You won't often want to look at other
versions. You'll be happy to know the original is there somewhere, standing by in case you
"undo". But there may come a time, perhaps while writing validation logic that concerns
transitions from one state to another, when you want to examine the other versions. This topic
explains the versions in some detail and shows how you can inspect them.
DevForce only versions "data properties", the properties that you persist to the database. It doesn't
version navigation properties nor the custom properties that you wrote.
Seeing is believing
This is easier to talk about with an example. Let's write a simple statement using the
CompanyName property of an umodified Customer object:
C# originalName = testCustomer.CompanyName;
VB originalName = testCustomer.CompanyName
The "originalName" variable is assigned the Current version of the CompanyName property.
Technically, the CompanyName property returns the Default version which might be other than the
Current under different circumstances. See below.
Because this entity is unmodified, the Current version is the same as the Original version
which is why we called the variable, originalName.
Let's change the Current version:
C# testCustomer.CompanyName = newName = "New Name";
VB testCustomer.CompanyName = newName = "New Name"
The current CompanyName will be newName; the original will remain originalName. To
prove it, we'll use the EntityAspect to go under the hood. EntityAspect has a GetValue
method with an overload that accepts one of the EntityVersion enums.
C#
// Get the current and original values
var curVal = (string) testCustomer.EntityAspect.GetValue("CompanyName",
EntityVersion.Current);
var origVal = (string) testCustomer.EntityAspect.GetValue("CompanyName",
EntityVersion.Original);

Assert.AreEqual(newName, curVal);
Assert.AreEqual(originalName, origVal);
Assert.AreNotEqual(curVal, origVal); // driving the point home.
VB
' Get the current and original values
Dim curVal = CStr(testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Current))
Dim origVal = CStr(testCustomer.EntityAspect.GetValue("CompanyName",
EntityVersion.Original))

Assert.AreEqual(newName, curVal)
Assert.AreEqual(originalName, origVal)
Assert.AreNotEqual(curVal, origVal) ' driving the point home.
Let's detach the entity and test the versions again:
C#
// Hold onto its current manager
var manager = testCustomer.EntityAspect.EntityManager;

// Detach
testCustomer.EntityAspect.RemoveFromManager();

// Get the current and original values again
curVal = (string) testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Current);
origVal = (string) testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Original);

// Both values are available, even in the detached state
Assert.AreEqual(newName, curVal);
Assert.AreEqual(originalName, origVal);
VB
' Hold onto its current manager
Dim manager = testCustomer.EntityAspect.EntityManager

' Detach
testCustomer.EntityAspect.RemoveFromManager()

' Get the current and original values again
curVal = CStr(testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Current))
origVal = CStr(testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Original))

' Both values are available, even in the detached state
Assert.AreEqual(newName, curVal)
Assert.AreEqual(originalName, origVal)
DevForce entities are "self-tracking". They retain both their current and original values even
when detached from an EntityManager. We can serialize them, deserialize them, hand them
around, import them in another EntityManager, or re-attach them to their former manager like
this:
C#
// Re-attach **and** ensure its //[[EntityState>>EntityState]]// is "modified"
manager.AttachEntity(testCustomer);
testCustomer.EntityAspect.SetModified();

// Get the current and original values again
curVal = (string) testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Current);
origVal = (string) testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Original);

// We've restored the modified entity
Assert.IsTrue(testCustomer.EntityAspect.EntityState.IsModified());
Assert.AreEqual(newName, curVal);
Assert.AreEqual(originalName, origVal);
VB
' Re-attach **and** ensure its //[[EntityState>>EntityState]]// is "modified"
manager.AttachEntity(testCustomer)
testCustomer.EntityAspect.SetModified()

' Get the current and original values again
curVal = CStr(testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Current))
origVal = CStr(testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Original))

' We've restored the modified entity
Assert.IsTrue(testCustomer.EntityAspect.EntityState.IsModified())
Assert.AreEqual(newName, curVal)
Assert.AreEqual(originalName, origVal)
Finally let's undo the pending changes and check the values again:
C#
testCustomer.EntityAspect.RejectChanges(); // undo

// Get the current and original values again
curVal = (string) testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Current);
origVal = (string) testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Original);

// Back to the initial unmodified entity
Assert.IsTrue(testCustomer.EntityAspect.EntityState.IsUnchanged());
Assert.AreEqual(originalName, curVal); // current restored to original
Assert.AreEqual(originalName, origVal);
Assert.AreEqual(curVal, origVal); // driving the point home.
VB
testCustomer.EntityAspect.RejectChanges() ' undo

' Get the current and original values again
curVal = CStr(testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Current))
origVal = CStr(testCustomer.EntityAspect.GetValue("CompanyName", EntityVersion.Original))

' Back to the initial unmodified entity
Assert.IsTrue(testCustomer.EntityAspect.EntityState.IsUnchanged())
Assert.AreEqual(originalName, curVal) ' current restored to original
Assert.AreEqual(originalName, origVal)
Assert.AreEqual(curVal, origVal) ' driving the point home.
The Original version
The Original value is the value retrieved from the database. Newly added entities don't have
an Original value. They have a Current value. They get an Original value when you save.
You can simulate a save by calling EntityAspect.AcceptChanges. You should be wary of doing that
although it can be useful in tests.
The Proposed version
DevForce entities implement System.ComponentModel.I EditableObject. That means they
have an additional level of do-undo.
IEditableObject has three methods:
Methods Summary
BeginEdit()
Begin editing the object. An edit session is open. While open, changes go into the
Proposed version.
CancelEdit() Cancel the edit. The edit session closes and the Proposed versions are discarded.
EndEdit() Ends the edit session and pushes the Proposed version values into the Current version.
You can inquire about the Proposed version any time.
C#
var proposed = (string) testCustomer.EntityAspect.GetValue("CompanyName",
EntityVersion.Proposed);
VB

Dim proposed = (string) testCustomer.EntityAspect.GetValue("CompanyName",
EntityVersion.Proposed)
The Default
There is a "Default" EntityVersion enum. Default is not really a version. Rather, it maps to the
version whose value would be returned by calling the property directly as we see in this
example:
C#
var value = testCustomer.CompanyName;
var default = (string) testCustomer.EntityAspect.GetValue("CompanyName",
EntityVersion.Default);
Assert.AreEqual(value, default ); // Always true.
VB
Dim value = testCustomer.CompanyName
Dim default1 = CStr(testCustomer.EntityAspect.GetValue("CompanyName",
EntityVersion.Default))
Assert.AreEqual(value, default1) ' Always true.
That's a tautology. You want to know how the Default is mapped.
Default maps to ... when ...
Current the entity is added, modified, unchanged, or detached.
Original the entity is deleted.
Proposed the entity is in the middle of an IEditableObject editing session.
Asking for a version that isn't defined
What if you ask for the Original of an added entity? An added entity doesn't have an Original
value. Rather than throw an exception or return a strange value, DevForce returns the Default
version.
DevForce always returns the Default version if the version asked for is undefined.
To give another example, the Proposed version is undefined unless the entity is in an open
IEditableObject edit session. If there is no open edit session and you ask for the Proposed
value, you get ... the Default value.
The EntityVersion Enum
EntityVersion is an enum whose values you should now appreciate.
Version Summary
Current The value that would be saved to the database.
Original The value as it was when the entity was last queried or saved.
Proposed
A changed value within an open IEditableObject session. It becomes the current value
when the session is closed by a call to EndEdit.
Default
Always the same as the property value. It is usually Current; it is Proposed during an
IEditableObject edit session and Original for a Deleted entity.
EntityVersion is a flag enumeration, meaning you can 'OR' the values together to form a
composite EntityVersion value for search purposes.
Take a snapshot
Last modified on March 23, 2011 22:59
You can take a snapshot of the entities in the entity cache and hold that snapshot as a
potential rollback or restore point.
CacheStateManager
To work with the cache, use the EntityManager's CacheStateManager.
Calling GetCacheState returns you an EntityCacheState that is a snapshot of the current state
of the cache. You can hold on to multiple EntityCacheStates and if you need to rollback to
one of them, just call RestoreCacheState.
You can also save the entity cache to a stream or file. See Save cache locally on how to do
this.

Validate
Last modified on March 23, 2011 10:47
Validation is the process of evaluating input and judging it valid or invalid. Such evaluation
subjects the input to a battery of validation rules that evaluate the input in the appropriate
context. For example, if the user enters a committed delivery date we might want to ensure
that:
The committed delivery date is reasonable in the abstract, e.g., occurs in the future
It is possible to deliver on that date given the availability of the desired products, and the
currently selected shipping method, and whether there is enough time to prepare the goods
for shipping
The order is shippable, e.g. the customers credit has been verified, the address is
legitimate, and the total is within the limits authorized for this user
Clearly such rules can be complex, involving not only the input value itself but also the state
of the target object (the order), facts about related objects (customer, shipper, product), and
aspects of the environment during the validation (time of day, the users role).
User input validation gets most of the attention but we need to validate programmatic inputs
as well. That delivery date could as easily be set by business logic or a web service request as
it is by a wayward click on a calendar control. The rules are the same for everyone, human
and machine.
Validation is hard to do well especially as the application grows and validation criteria
change. Common failings include:
Missing and incorrect validity checks
Inconsistent checking
Failure to validate at the right times
Poor communication with end-users
Inadequate mechanisms for correcting mistakes
Enterprise application developers are looking for a robust validation system that operates
consistently and reliably across a large application. Robust validation cuts both vertically
and horizontally:
We validate vertically when we validate several times in multiple layers of the application.
We want to validate in the client UI layer so we can give immediate feedback to the user. We
may need to validate again when we save, even though the objects we save are no longer on
screen. We may even need to validate again on the server side to protect against
misadventure coming from outside the relative safety of the hosted environment.
We validate horizontally when we apply the same mechanisms uniformly across all
modules of the application. If the user can set the delivery date on any of several screens,
the same rules ought to apply unless, of course, there is something special about a
particular screen.
Validation concepts
The validation infrastructure provided by DevForce is made up of a collection of
interoperating validation components that are both easy to use and capable of handling
sophisticated scenarios. The developer can:


Capabilities

Generate validity checking into business objects automatically via the DevForce Object
Mapper.
Write rules of any complexity. The developer can draw upon pre-defined rules (required
value, range check, field length) or write custom rules of any complexity, including rules that
compare multiple fields and span multiple objects.
Validate any kind of object, not just objects that derive from base business classes.
Trigger validity checking at any time such as upon display, before save, or when setting
properties. The engine can fire pre-set to block critically errant data from entering the
object or fire post-set to accommodate temporarily invalid values. The UI can inspect the
engine for rules of interest, fire them, and adjust the display accordingly. It could color a text
box, for example, or hide a portion of the form until applicable criteria were met.
Display a localized message in the UI without special programming. The UI could display just
the validation failed message but it might also show warnings or ok messages and it
might supplement the message be re-directing the application focus to the offending object
and property. Each rule returns a rich, extensible object with all the information necessary
for the developer to deliver a helpful response.
Discover rules in the code or retrieve them at runtime from a central store. The engine
automatically discovers rules in the code and can acquire rules defined externally in
configuration XML, a database, or some other store of rules. The application can inspect,
add, and remove rules at any time.
Leverage rules inheritance. Rules defined in base classes propagate to their derived classes
where they are inherited or overridden.
Adjust validation behavior based on a custom validation context. The developer must have
the flexibility to convey custom information to the validation process to cope with the variety
of situational factors that arise in real applications.
Inspect and intervene as the engine validates. The application can monitor the engines
progress and interrupt, modify, or terminate a validation run at any point.
Verification vs.validation
The DevForce validation mechanism is called verification and all of its components are
named with some variation on this word. We mean to try neither your patience nor your
vocabulary. We would call our offering validation if we could.
However, Microsoft uses the term validation throughout .NET. It appears in Windows
Presentation Foundation (WPF) and Windows Workflow Foundation (WWF) namespaces and
in the Enterprise Library as well. Microsoft also uses the following class names:
ValidationError, ValidationErrorCollection, ValidationManager, ValidationResult,
ValidationRule, ValidationStatus, ValidationType
IdeaBlade is integrating DevForce with Microsofts WPF and WWF. You are likely doing the
same. We will all become confused if we cannot easily distinguish among the same or very
similar names.
So verification it is. We will continue to say validation when we speaking in general
terms; we will use the term verification (and its variants) when we refer specifically to the
DevForce classes located in the IdeaBlade.Verification namespace.
What about WPF and Silverlight Validation?
We cant leave this digression without a parting comment about validation in Microsofts
Windows Presentation Foundation.
WPF validation concentrates on presentation of validation results within a WPF user
interface. This is a vital aspect of any validation strategy. At present, most applications punish
the user for the developers own design failings. We need better UIs and better means to guide
users rather than humiliate them.
DevForces verification concentrates on the validation process. It complements WPF by
producing the rich validation results necessary to deliver an effective user experience. We will
address the integration of these mechanisms in a separate document.
Overview of validation mechanics
All validation in DevForce is performed by a VerifierEngine. Every EntityManager contains
its own instance of a VerifierEngine, accessible via its VerifierEngine property.
VerifierEngines can also be created and used independently.
The VerifierEngine class is discussed in more detail elsewhere, but the critical idea here is
that every VerifierEngine contains a list of verifier instances. A verifier instance is an
instance of some subclass of the Verifier class.
The VerifierEngine offers a set of methods that allow collections of these verifier instances to
be evaluated sequentially against an instance of a .NET class. This is the process of
"performing a validation".
The object to be validated can be a DevForce entity but it doesnt have to be. The object can
be of any concrete type.
Each verifier execution produces a VerifierResult. The engine accumulates these results in a
VerifierResultCollection as it proceeds and returns the entire collection as its own result.


Adding Verifiers to a VerifierEngine
Verifiers can be added to a VerifierEngine in two ways:
The engine can discover them automatically by inspecting the .NET types for verifier
attributes.
The developer can add them programmatically.
The application can combine these methods.
Validation discovery
Whenever a VerifierEngine is asked to "validate" a type, its first step is to discover all of the
verifiers that are applicable to that type. Some of these verifiers are defined using property
level attributes that may be applied to the type being validated; but verifiers may also be
defined in .NET code, and even in XML. The VerifierEngine discovers all of these verifiers,
and creates instances of each in an internal collection. These instances will be used to perform
the actual validations.
Validation using attributes
Most verifier instances are responsible for the validation a single property on a single target
type. Validations of this form are usually specified by marking up the target type's properties
with a variety of validation attributes.

These validation attributes can either have been automatically generated on the type by
DevForce or may have been added directly to the class by the developer ( usually via a
metadata buddy class). Many of the most basic "database constraints" that arise from the
process of using the Entity Data Model Designer to map a class will automatically appear in
the generated code as validation attributes on various properties. These will appear as
StringLength or RequiredValue attributes.
Validation configuration
Each verifier instance has its own properties which tell the VerifierEngine the conditions
under which it is applicable. For example, you can define a verifier so that it runs before a
proposed new property value is pushed into the business object; or after; or even both (though
that is unusual). You also want most verifiers to run whenever an entire instance of a type is
being validated. To specify these things, you specify the ExecutionModes on an instance of
the VerifierOptions type.
Performing a validation
The VerifierEngine has several overloads available to actually cause a validation to occur.
The methods can be called directly, but they will also be called automatically by the
DevForce infrastructure at the following points:
Whenever any entity within an EntityManager has any of its property values changed. In this
case the EntityManager sees the change to the entity and internally calls its VerifierEngine to
perform the validation.
Whenever an entity is saved, the EntityServer "validates" every entity before it is saved. If
any do not validate, the save is canceled.
Different kinds of validation
These are two different kinds of validation.
In the case of a change to a property value, we really only want to perform the minimum
number of validations that are relevant to the property being changed. This is called a
property validation and there are specific methods on the EntityManager that are intended for
this purpose.
In the case of a save, we really want to "validate" the entire entity. This will mean
"validating" every property along with any validations that cross properties or possibly even
involve related objects. This is referred to as an instance validation. Again there is a specific
method on the VerifierEngine for this purpose.
Result of a validation
Regardless of which form of validation is performed the result of a validation is always a
VerifierResultsCollection which as the name suggests, is a collection of VerifierResults. Each
VerifierResult contains a reference to the object being validated, the validation instance used
to perform the validation and most importantly the "result" of the validation. VerifierResults
that represent "errors" are automatically added to each entities EntityAspect.ValidationErrors
collection.




Generate automatic validation attributes
The easiest point of entry to DevForce validation is through the DevForce extensions to the
Entity Data Model Designer. The idea is that we can get a certain set of automatic validation
code generated for us simply as a side effect of setting up our domain model. This page
details how to use Visual Studio Entity Data Model Designer to automatically generate
validation attributes.


Validation-related code generation options
1. Open an Entity Data Model in the Visual Studio Entity Data Model Designer.
2. Display the Properties panel and then click in white space in the designer window to display
the properties of the ConceptualEntityModel. In the DevForce Code Generation section, note
the property Validation Attribute Mode:

3. You can choose to have DevForce generate DevForce-style validation attributes for entities
and their properties, or .NET-style.
We recommend that you use use DevForceVerification unless you have a compelling reason to do
otherwise (e.g., you have a large amount of code that already uses the .NET attributes and facilities).
DevForce verification provides a superset of the capabilities provided by .NET validation.
Generated property code
Here well show you the results of the three different values for Validation Attribute Mode:
Generate DevForceVerification Attributes

Here is the FirstName property of an Employee object as generated with the settings shown
above:
C#
#region FirstName property
/// <summary>Gets or sets the FirstName. </summary>
[Bindable(true, BindingDirection.TwoWay)]
[Editable(true)]
[Display(Name="FirstName", AutoGenerateField=true)]
[IbVal.StringLengthVerifier(MaxValue=30, IsRequired=true,
ErrorMessageResourceName="Employee_FirstName")]
[DataMember]
public string FirstName {
get { return PropertyMetadata.FirstName.GetValue(this); }
set { PropertyMetadata.FirstName.SetValue(this, value); }
}
#endregion FirstName property
VB
#Region "FirstName property"

''' <summary>Gets or sets the FirstName. </summary>
<Bindable(True, BindingDirection.TwoWay), Editable(True), _
Display(Name:="FirstName", AutoGenerateField:=True), _
IbVal.StringLengthVerifier(MaxValue:=30, IsRequired:=True, _
ErrorMessageResourceName:="Employee_FirstName"), DataMember()> _
Public Property FirstName() As String
Get
Return PropertyMetadata.FirstName.GetValue(Me)
End Get
Set(ByVal value As String)
PropertyMetadata.FirstName.SetValue(Me, value)
End Set
End Property
#End Region ' FirstName property
IbVal is an alias for the IdeaBlade.Validation namespace, defined at the top of the code file.
The IbVal.StringLengthVerifier sets a maximum length on the (text) value, and its IsRequired
argument declares the property non-nullable.
Generate .NET validation attributes

Here is the generated code that the above settings in the EDM designer:
C#
#region FirstName property

/// <summary>Gets or sets the FirstName. </summary>
[Bindable(true, BindingDirection.TwoWay)]
[Editable(true)]
[Display(Name = "FirstName", AutoGenerateField = true)]
[Required()]
[StringLength(30)]
[DataMember]
public string FirstName {
get { return PropertyMetadata.FirstName.GetValue(this); }
set { PropertyMetadata.FirstName.SetValue(this, value); }
}
#endregion FirstName property
VB
#Region "FirstName property"

''' <summary>Gets or sets the FirstName. </summary>
<Bindable(True, BindingDirection.TwoWay), Editable(True), _
Display(Name:="FirstName", AutoGenerateField:=True), _
Required(), _
StringLength(30), _
DataMember()> _
Public Property FirstName() As String
Get
Return PropertyMetadata.FirstName.GetValue(Me)
End Get
Set(ByVal value As String)
PropertyMetadata.FirstName.SetValue(Me, value)
End Set
End Property
#End Region ' FirstName property
This time the non-nullability (i.e., Required) and string length constraints are specified using
the .NET validation attributes.
Generate No Verification or Validation Attributes

This setting results in the absence of validation-related attributes of any sort:
C#
#region FirstName property

/// <summary>Gets or sets the FirstName. </summary>
[Bindable(true, BindingDirection.TwoWay)]
[Editable(true)]
[Display(Name = "FirstName", AutoGenerateField = true)]
[DataMember]
public string FirstName {
get { return PropertyMetadata.FirstName.GetValue(this); }
set { PropertyMetadata.FirstName.SetValue(this, value); }
}
#endregion FirstName property
VB
#Region "FirstName property"

''' <summary>Gets or sets the FirstName. </summary>
<Bindable(True, BindingDirection.TwoWay), Editable(True), _
Display(Name:="FirstName", AutoGenerateField:=True), DataMember()> _
Public Property FirstName() As String
Get
Return PropertyMetadata.FirstName.GetValue(Me)
End Get
Set(ByVal value As String)
PropertyMetadata.FirstName.SetValue(Me, value)
End Set
End Property
#End Region ' FirstName property


Add custom validation attributes
Last modified on May 23, 2011 17:11
Default code generation of your entity model will automatically add some validation
attributes to your entity properties. You can also have code generation generate custom
validation attributes onto your entity properties.
These following verifier attributes are automatically added to the code that DevForce
generates based on the property attributes defined in the Entity Framework Designer:
if a property is non-nullable the RequiredValueVerifier is added
if a property has a backing column with a maximum string length, a StringLengthVerifier is
added.
These attributes appear as follows in the generated code:
C#
[IbVal.RequiredValueVerifier( ErrorMessageResourceName="Employee_Id")]
public long Id { ... }

[IbVal.StringLengthVerifier(MaxValue=30, IsRequired=true,
ErrorMessageResourceName="Employee_LastName")]
public string LastName { ... }
VB
<IbVal.RequiredValueVerifier(ErrorMessageResourceName:="Employee_Id")> _
Public ReadOnly Property Id() As Long
...
End Property
<IbVal.StringLengthVerifier(MaxValue:=30, IsRequired:=True,
ErrorMessageResourceName:="Employee_LastName")> _
Public ReadOnly Property LastName() As String
To add additional verifiers to your entities, you can programmatically add verifiers, as we've
seen earlier. But you have another option too: you can use a "buddy" class containing
metadata to be applied to entity properties. In the buddy class you define additional validation
attributes for your entity properties, and "link" the buddy class to the entity class by placing
the MetadataType attribute on the class. Here's an example to make this clearer:
C#
[MetadataType(typeof(EmployeeMetadata))]
public partial class Employee { ... }

public class EmployeeMetadata {

[RequiredValueVerifier()]
public static string City;

[DateTimeRangeVerifier(MinValue="1/1/2000", MaxValue="12/31/2010")]
public static DateTime? HireDate;

[RegexVerifier("Home phone", "USPhone")]
public static string HomePhone;
}
VB
<MetadataType(GetType(EmployeeMetadata))> _
Public Partial Class Employee
End Class

Public Class EmployeeMetadata

<RequiredValueVerifier> _
Public Shared City As String

<DateTimeRangeVerifier(MinValue := "1/1/2000", MaxValue := "12/31/2010")> _
Public Shared HireDate As System.Nullable(Of DateTime)

<RegexVerifier("Home phone", "USPhone")> _
Public Shared HomePhone As String
End Class
The verifier attributes defined in the buddy class will take precedence and override the same verifier
attribute for the same property in the generated code. For example, if you have a generated
Employee.LastName StringLengthVerifierAttribute with IsRequired = true, and you create an
Employee buddy class and add a StringLengthVerifierAttribute with IsRequired = false to the
LastName property, then the LastName will no longer be required.
The precedence described above will only take place for standard DevForce verifier attributes. If you
have created your own custom verifier attribute, and define it in the buddy class, code generation
will still discover it. But the existing generated DevForce verifier attributes will not be overridden.
The verifiers may be a bit contrived here (unless you really do want to hire only US
employees in this decade), but should give you an idea of what you can do. Any of the
DevForce validation attributes, such as any of the range verifiers Int32RangeVerifierAttribute,
Int64RangeVerifierAttribute, DecimalRangeVerifierAttribute, DoubleRangeVerifierAttribute,
DateTimeRangeVerifierAttribute, etc.) or RegexVerifierAttribute, or any custom validation
attributes you write which extend a DevForce verifier attribute, can be used.
There are a few rules to follow, to ensure that your attributes are found:
Be sure to add the MetadataType attribute to the class you will be providing metadata
for. Here we've decorated the Employee class with the attribute.
The buddy class can be standalone or nested, and should be public or internal, or private if
used only in Desktop applications.
The buddy class should define public fields or properties having the same name as the
property in the class for which it's defined. These members can be either static or defined on
the buddy class instance. In the case above, the Employee class should have properties
named "City", "HireDate", and "HomePhone".
The MetadataType attribute is defined in IdeaBlade.Core.ComponentModel.DataAnnotations
for Silverlight applications, and in System.ComponentModel.DataAnnotations for desktop
applications. The attribute functions the same in either environment.
DevForce will look for the MetadataType attribute as it is generating code for your entities.
Always remember to regenerate your models to ensure these new attributes are discovered and
included in the generated code.

Consider predefined verifiers
Last modified on March 22, 2011 15:18
Contents
DevForce provides a collection of predefined verifiers that can either be used as is, or
subclassed to add additional behaviours.


All of the verifiers listed below, with the exception of the DelegateVerifier<T>, are
subclasses of the abstract base class PropertyValueVerifier.
Verifier Description
RequiredValueVerifier A verifier that checks that a null value has not been returned.
StringLengthVerifier A verifier that checks that a string value's length is within a range.
RegexVerifier
A verifier that checks that a string value matches a specified regular
expression.
RangeVerifier<T>
The abstract base class for all other RangeVerifiers. This class and all of its
subclasses provide validation that a value is within a specified range. If one
of the provided subclasses does not match the type of value that you need
for a range validation then subclass this type.
Int32RangeVerifier A RangeVerifier for Int32 values.
Int64RangeVerifier A RangeVerifier for Int64 values.
DoubleRangeVerifier A RangeVerifier for Double values.
DecimalRangeVerifier A RangeVerifier for Decimal values.
DateTimeRangeVerifier A RangeVerifier for DateTime values.
ListVerifier A verifier that checks if a value is among those in a specified list.
PropertyValueVerifier<T>
An abstract PropertyValueVerifier that is strongly typed as to the type of
parent object being validated. (Not the type of the value being validated).
May be used to create strongly classed subclasses of the
PropertyValueVerifier.
DelegateVerifier<T>
The abstract base class for all custom validations that cannot be written by
subclassing one of the other verifiers provided above.
Create a custom verifier
DevForce ships with a number of pre-defined verifiers that can be customized in a variety
of ways: examples include the DateTimeRangeVerifier, the RegexVerifier, the
StringLengthVerifier, the RequiredValueVerifier, and a number of others. In addition, it
defines a generic DelegateVerifier<T> that provides unlimited verification capabilities: you
can use it to define any sort of rule you need or can imagine.
There are several ways to create a verifier, but in general the easiest ways involve starting
with an existing one and modifying it to suit.


Creating a customized version of a standard (provided) verifier
The method GetHireDateRangeVerifier below illustrates the creation of a 'customized'
verifier by simply creating one of the standard DevForce verifiers with specific parameters, in
this case, the DateTimeRangeVerifier. Other provided verifiers include many others that are
specific to .NET simple types, including DecimalRangeVerifier, DoubleRangeVerifier,
Int32RangeVerifier, and so forth. There is a ListVerifier, a Regex Verifier, a
NamedRegexPattern verifier, and a number of others. All are defined in the
IdeaBlade.Validation namespace.
The constructor for the DateTimeRangeVerifier provides for all of the configuration we need.
It permits us to specify the target business object type for the rule, the property on that type
whose setting will trigger the running of the rule, whether a non-null value is required when
that property is set, and the dates that define the valid range:
C#
private static Verifier GetHireDateRangeVerifier(DateTime minHireDate, DateTime maxHireDate)
{
Verifier v = new DateTimeRangeVerifier(
typeof(Employee), // Type of the object being verified
Employee.PropertyMetadata.HireDate.Name, // Property trigger
false, // Non-null value is not required
minHireDate, true, // starting min date (inclusive)
maxHireDate, false); // ending max date (exclusive)
return v;
}
VB
Private Shared Function GetHireDateRangeVerifier( _
minHireDate as DateTime, maxHireDate as DateTime) As Verifier
Dim v As Verifier = New DateTimeRangeVerifier( _
GetType(Employee), _
Employee.PropertyMetadata.HireDate.Name, _
False, _
minHireDate, True, _
maxHireDate, False)
Return v
End Function
If you need to improve upon the default message produced by the above verifier, you can take
control of the messaging by setting the verifiers VerifierArgs.ErrorMessageInfo.Error. For
example, if you insert the following statement right before the return statement in the above
method, your message will be the one users see:
C#
v.VerifierArgs.ErrorMessageInfo.ErrorMessage = String.Format(
"The HireDate must fall on or after the Company's launch date of {0} " +
"and before one month from today ({1}).",
minHireDate.ToShortDateString(), maxHireDate.ToShortDateString());
VB
v.VerifierArgs.ErrorMessageInfo.ErrorMessage = String.Format( _
"The HireDate must fall on or after the Company's launch date of {0} " _
& "and before one month from today ({1}).", _
minHireDate.ToShortDateString(), maxHireDate.ToShortDateString())
Subclassing a pre-defined verifier
Another way to create a custom verifier is to subclass one of the pre-defined verifiers that are
in the IdeaBlade.Validation namespace. In the following code samples below, we will create a
custom verifier that checks that a given GUID property does NOT equal Guid.Empty. We will
do this by subclassing a PropertyValueVerifier to define a custom class called
NotEmptyGuidVerifier.
Step 1: Create the custom NotEmptyGuidVerifier class by inheriting it from the
PropertyValueVerifier class. The constructor takes 2 parameters, an entityType and a
propertyName. This allows us to pass any entity and any Guid property.
C#
public class NotEmptyGuidVerifier : PropertyValueVerifier {

public NotEmptyGuidVerifier(Type entityType, String propertyName,
String displayName = null, bool? shouldTreatEmptyStringAsNull = null)
: base(new PropertyValueVerifierArgs(entityType, propertyName, false,
displayName, shouldTreatEmptyStringAsNull)) { }

protected override VerifierResult VerifyValue(object itemToVerify, object valueToVerify,
TriggerContext triggerContext, VerifierContext verifierContext) {
var aGuid = (Guid)valueToVerify;
var result = (aGuid != Guid.Empty);
return new VerifierResult(result);
}
}
}
VB
Public Class NotEmptyGuidVerifier
Inherits PropertyValueVerifier
Public Sub New(ByVal entityType As Type, ByVal propertyName As String, _
Optional ByVal displayName As String = Nothing, Optional ByVal _
shouldTreatEmptyStringAsNull? As Boolean = Nothing)
MyBase.New(New PropertyValueVerifierArgs(entityType, propertyName, _
False, displayName, shouldTreatEmptyStringAsNull))
End Sub
Protected Overrides Function VerifyValue(ByVal itemToVerify As Object, _
ByVal valueToVerify As Object, ByVal triggerContext_Renamed As _
TriggerContext, ByVal verifierContext_Renamed As VerifierContext) _
As VerifierResult
Dim aGuid = CType(valueToVerify, Guid)
Dim result = (aGuid IsNot Guid.Empty)
Return New VerifierResult(result)
End Function
End Class
Step 2: Wrap the NotEmptyGuidVerifier class in a method that returns a Verifier. We will call
this method "CheckForEmptyGuidVerifier".
C#
private static Verifier CheckForEmptyGuidVerifier(Type entityType, string propertyName) {
Verifier v = new EmptyGuidVerifier(entityType, propertyName);
v.VerifierArgs.ErrorMessageInfo.ErrorMessage =
String.Format("{0} cannot be empty", propertyName);
return v;
}
VB
Private Shared Function CheckForEmptyGuidVerifier(ByVal entityType _
As Type, ByVal propertyName As String) As Verifier
Dim v As Verifier = New EmptyGuidVerifier(entityType, propertyName)
v.VerifierArgs.ErrorMessageInfo.ErrorMessage = String.Format( _
"{0} cannot be empty", propertyName)
Return v
End Function
Step 3: Add the method to the list of Verifiers that is defined inside the VerifierProvider"
class that implements the IVerifierProvider interface. Note that in this example, we are using
the verifier to validate an Order.CustomerID property (presumably of type GUID).
C#
public class VerifierProvider : IVerifierProvider {

public IEnumerable<Verifier> GetVerifiers(object verifierProviderContext) {
List<Verifier> verifiers = new List<Verifier>();

//In this example, we are passing a type Order and validating the Order.CustomerID property
verifiers.Add(CheckForEmptyGUIDVerifier(typeof(Order),
Order.PropertyMetadata.CustomerID.Name));

return verifiers;
}
}
VB
Public Class VerifierProvider
Implements IVerifierProvider
Public Function GetVerifiers(ByVal verifierProviderContext As _
Object) As IEnumerable(Of Verifier)
Dim verifiers As New List(Of Verifier)()

'In this example, we are passing a type Order and validating
' the Order.CustomerID property
verifiers.Add(CheckForEmptyGUIDVerifier(GetType(Order), _
Order.PropertyMetadata.CustomerID.Name))
Return verifiers
End Function
End Class
Step 4: And finally, let's test our newly created verifier.
C#
public void GenericVerifierForGUIDEmpty() {
var mgr = new NorthwindIBEntityManager();
var anOrder = mgr.Orders.FirstOrNullEntity();
anOrder.CustomerID = Guid.Empty;

Assert.IsTrue(anOrder.EntityAspect.ValidationErrors.Count > 0,
"CustomerID is assigned to GUID.Empty");
VB
Public Sub GenericVerifierForGUIDEmpty()
Dim mgr = New NorthwindIBEntityManager()
Dim anOrder = mgr.Orders.FirstOrNullEntity()
anOrder.CustomerID = Guid.Empty

Assert.IsTrue(anOrder.EntityAspect.ValidationErrors.Count > 0, _
"CustomerID is assigned to GUID.Empty")
End Sub
Now lets recap what we just did.
1. We created our generic verifier by subclassing a PropertyValueVerifier class that is pre-
defined in the IdeaBlade.Validation namespace.
2. We wrap up the class inside a method that returns a Verifier. This is a required signature to
add the verifier to the VerifierEngine.
3. We add the method to the list of Verifiers that is defined inside a class that implements an
IVerifierProvider interface. In our example, this class is called VerifierProvider.
4. Using a TestMethod, we test the Verifier by retrieving anOrder and assigning its CustomerID
to Guid.Empty. The Assert.IsTrue method should succeed as
anOrder.EntityAspect.ValidationErrors.Count should be more than 0.
Creating a completely custom verifier using the DelegateVerifier
Despite the imposing name, the DelegateVerifier is really just a completely custom verifier.
With this verifier you define the type of the object to verify, when and how to apply the
verifier, and the validation to be performed. The DelegateVerifier is particularly useful for
verifying multiple properties on a type, and for cross-type validation.
When you create the custom verifier you provide a VerifierCondition, which is really just a
function which performs the actual validation wanted. The function returns a VerifierResult,
indicating whether the validation succeeded or not.
You can also provide the constructor with the an ApplicabilityConstraint. Another imposing
term, but it's just a function which given an object and some "context", determines whether
the verifier should be run, in other words, whether it's applicable.
As with other verifiers, you can also set the VerifierOptions. These options control when the
verifier will be executed, and what to do when a validations fails.
The verifier also needs one or more "triggers", one or more members, either on the type to be
verified or another type, which "trigger" validation. Usually a trigger is the setter for a
property, but it can also be a method call. If the custom validation isn't actually triggered by a
property set but instead only on the object as a whole, the triggers can indicate the properties
of interest.
Triggers
Consider a constraint that specifies that the HireDate for an Employee must be later than the
Employees BirthDate. That seems a pretty reasonable requirement, but suppose when the
user enters a HireDate of today, this rule is found to have been violated. But the Employee
really was hired today, and the problem is that the BirthDate previously entered for the
Employee was in error, specifying the year 2015 when it should have said 1985. If we prevent
the new HireDate value from being entered into that property, well subject the user to a lot of
unnecessary work. Shell have to clear the new HireDate, even though it is entirely correct,
and then go fix the BirthDate value, and then come back and re-enter the new HireDate value,
even though she got it right the first time. Users dont have a lot of tolerance for this sort of
thing! Its confusing, irritating, or often both.
A verifier that applies to BirthDate doesnt have to be triggered by a change to that property.
You can, instead or additionally specify that you want it called when the value of
HireDate is changed. You can even set it to be triggered by a change to a property of some
other type; and not just any instance of that type, but one that happens to be specifically
related. For example, suppose you have a rule that says that the OrderDate on an Order taken
by Employee X must be greater than or equal to that Employees HireDate. You could define
this rule (as a verifier) on the Employee type, but specify that it should be triggered not only
by a change to Employee.HireDate, but equally by a change to the OrderDate property of any
Order written by that Employee!
Example
With some terminology out of the way, let's look at a simple sample. Here we'll define a
custom verifier for the Employee class to require that the employee's birth date precedes her
hire date. The VerifierCondition is simple: the BirthDate must fall before the HireDate. The
triggers are the "BirthDate" and "HireDate" properties on the Employee, and options here tell
the engine that verification should be performed after either of these properties is set, and for
instance-level validation.
C#
private static Verifier GetBornBeforeHiredVerifier() {
string description = "Must be born before hired.";
DelegateVerifier<Employee> v =
new DelegateVerifier<Employee>(description,
BornBeforeHiredCondition);

v.AddTriggers(Employee.PropertyMetadata.BirthDate.Name,
Employee.PropertyMetadata.HireDate.Name);

v.VerifierOptions.ExecutionModes =
VerifierExecutionModes.InstanceAndOnAfterSetTriggers;
return v;
}

private static VerifierResult BornBeforeHiredCondition(
Employee pEmp, TriggerContext pTriggerContext,
VerifierContext pVerifierContext) {

if (pTriggerContext != null &&
// We are not checking the proposed value
// because don't expect to call it preset
pTriggerContext.Timing == TriggerTiming.BeforeSet) {
throw new VerifierException(
"BornBeforeHired verifier not implemented for Preset");
}
return new VerifierResult(pEmp.BirthDate < pEmp.HireDate);
}
VB
Private Shared Function GetBornBeforeHiredVerifier() As Verifier
Dim description As String = "Must be born before hired."
Dim v As New DelegateVerifier(Of Employee)(description, _
AddressOf BornBeforeHiredCondition)

v.AddTriggers(Employee.PropertyMetadata.BirthDate.Name, _
Employee.PropertyMetadata.HireDate.Name)

v.VerifierOptions.ExecutionModes = _
VerifierExecutionModes.InstanceAndOnAfterSetTriggers
Return v
End Function

Private Shared Function BornBeforeHiredCondition(ByVal pEmp _
As Employee, ByVal pTriggerContext As TriggerContext, _
ByVal pVerifierContext As VerifierContext) As VerifierResult

' We are not checking the proposed value
' because don't expect to call it preset
If pTriggerContext IsNot Nothing AndAlso pTriggerContext.Timing = _
TriggerTiming.BeforeSet Then
Throw New VerifierException( _
"BornBeforeHired verifier not implemented for Preset")
End If
Return New VerifierResult(pEmp.BirthDate < pEmp.HireDate)
End Function
In the above code we define a DelegateVerifier that returns, as always a VerifierResult. We
add two triggers to our verifier, since it tests the relative value of two different properties, and
we want a change in either to result in re-application of our validity test.
BeforeSet Versus AfterSet Execution and Its Interaction With ErrorNotificationMode
This section requires an understanding of the use of VerifierOptions to configure validation.
Note that we have also the VerifierExecutionModes for this verifier set to
InstanceAndOnAfterSetTriggers . This doesnt matter so much if the
VerifierErrorNotificationMode is set at the default of Notify . Under that setting a verification
failure will not result in an exception that blocks the commitment of the proposed value into
the business object. But if, on the other hand, the VerifierErrorNotificationMode were set to
ThrowException or NotifyAndThrowException then running the verifier in AfterSet rather
than BeforeSet mode would be essential.
To understand why, consider what would happen if a user discovered that both the HireDate
and BirthDate values currently set for a given Employee were incorrect, even though valid
according to the born before hired rule. To correct them, she needs to change both values;
but, upon changing the BirthDate value, the verifier was executed and discovered that the new
BirthDate value caused the HireDate and BirthDate values to be invalid relative to one
another. The user planned to correct this problem by entering a new HireDate value which
would bring the two values back into relative validity. But if the verifier triggered by the
BirthDate change ran BeforeSet and threw an exception, the proposed new value would be
prevented by the exception from entering the business object. The user might then try entering
the new HireDate value first; but this might also cause a BeforeSet exception. So she would,
in fact, be unable to correct the property values for the invalid Employee.
It is therefore a good idea to set the VerifierOptions for such a cross-property verifier so that
either
1) The verifier runs AfterSet.
or
2) The VerifierErrorNotificationMode is set to Notify.
Thus any validation failure will not throw an exception during and before the 'set' of a
temporarily invalid but necessary intermediate value.
Cross-Type Verifiers
A cross-type verifier defines a rule whose application requires the inspection of at least one
business object of a type different than the business object being validated. For example,
suppose you have a rule that says the OrderDate on any Order may not be earlier than the
HireDate of the Employee writing the Order. Clearly the application of this rule requires the
inspection of at least one Order and one Employee. If the change that triggers the verifier is to
the Employee.HireDate rather than the OrderDate of an Order, then all Orders associated with
the changed Employee must be checked.
Note that such a verifier needs to have multiple triggers associated with it. In the case of our
example, it should be executed whenever either the HireDate of an Employee, or the
OrderDate of an Order, is changed.
There is another issue with such a verifier: where should it be defined? DevForce initiates its
discovery process for the verifiers associated with a particular type when the first instance of
that type is retrieved into the cache. So if we define our Employee.HireDate /
Order.OrderDate verifier in the Employee class, it will be discovered automatically when the
first Employee is retrieved during a given application session. But if an Order is retrieved and
changed before any Employee is downloaded, the verifier will not be discovered and will not
be run. The same issue exists, in reverse, if we choose to define the verifier in the Order class.
Now if we retrieve and change an Employee before retrieving any Orders, again the verifier
wont be discovered, since it is not defined on the Order type.
The solution to this conundrum is to order DevForce explicitly to discover the verifiers for
any type that may have verifiers involving a type other than itself. For example, to get
EntityManager _em1 to discover the verifiers for the Order type, you can use the following
statement:
C# myEntityManager.VerifierEngine.DiscoverVerifiers(typeof(Order));
VB myEntityManager.VerifierEngine.DiscoverVerifiers(GetType(Order))
This should be done before there is any chance that one of the verifiers defined in the Order
class might be needed for some other type.
We'll define a DelegateVerifier for the cross-type validation to be performed in our
sample. We're defining the verifier for the Order class, and then defining triggers for both the
OrderDate property of Order and the HireDate property of Employee. We also define the
"path" from Employee to Orders. We could have inverted this setup and defined the verifier
for the Employee type; it doesn't really matter to DevForce.
C#
/// <summary>
/// Implement IVerifierProvider interface to give
/// DevForce the verifiers in use at run time.
/// </summary>
public class VerifierProvider : IVerifierProvider {

public IEnumerable<Verifier> GetVerifiers(
object verifierProviderContext) {
List<Verifier> verifiers = new List<Verifier>();
verifiers.Add(GetOrderDateAfterHiredVerifier());
return verifiers;
}
}

///<summary>Get the OrderDateAfterHired Verifier.</summary>
private static Verifier GetOrderDateAfterHiredVerifier() {

string description =
"OrderDate must be after the sales rep's HireDate.";
DelegateVerifier<Order> v = new DelegateVerifier<Order>(
description, OrderDateAfterHiredCondition);

v.VerifierOptions.ExecutionModes =
VerifierExecutionModes.InstanceAndOnAfterSetTriggers;

v.AddTrigger(Order.PathFor(o => o.OrderDate));
v.AddTrigger(new TriggerLink(new TriggerItem
(typeof(Employee), Employee.PathFor(e => e.HireDate)),
e => ((Employee)e).Orders,
// Path from trigger (Employee) to Order
true)); // True = that path returns multiple orders
return v;
}

///<summary>
///Implementor of the OrderDateAfterHired Verifier condition.
///</summary>
private static VerifierResult OrderDateAfterHiredCondition(
Order target, TriggerContext triggerContext,
VerifierContext pVerifierContext) {

if (triggerContext != null &&
triggerContext.Timing == TriggerTiming.BeforeSet) {
throw new VerifierException(
"OrderDateAfterHired verifier not implemented for Preset");
}
bool isOk =
target.OrderDate.HasValue &&
target.SalesRep.HireDate.HasValue &&
target.OrderDate.Value >= pTarget.SalesRep.HireDate.Value;

return new VerifierResult(isOk);
}
VB
'''<summary>Get the OrderDateAfterHired Verifier.</summary>
Private Shared Function GetOrderDateAfterHiredVerifier() As Verifier
Dim description As String = _
"OrderDate must be after the sales rep's HireDate."
Dim v As New DelegateVerifier(Of Order)(description, _
AddressOf OrderDateAfterHiredCondition)
v.VerifierOptions.ExecutionModes = _
VerifierExecutionModes.InstanceAndOnAfterSetTriggers
v.AddTrigger(Order.PathFor(Function(o) o.OrderDate))
' Path from trigger (Employee) to Order
v.AddTrigger(New TriggerLink(New TriggerItem( _
GetType(Employee), Employee.PathFor(Function(e) e.HireDate)), _
Function(e) (CType(e, Employee)).Orders, True)) _
' True = that path returns multiple orders
Return v
End Function

'''<summary>
'''Implementor of the OrderDateAfterHired Verifier condition.
'''</summary>
Private Shared Function OrderDateAfterHiredCondition(ByVal target _
As Order, ByVal triggerContext As TriggerContext, _
ByVal verifierContext As VerifierContext) As VerifierResult
If triggerContext IsNot Nothing AndAlso triggerContext.Timing = _
TriggerTiming.BeforeSet Then
Throw New VerifierException( _
"OrderDateAfterHired verifier not implemented for Preset")
End If
Dim isOk As Boolean = target.OrderDate.HasValue AndAlso _
pTarget.SalesRep.HireDate.HasValue AndAlso _
pTarget.OrderDate.Value >= target.SalesRep.HireDate.Value
Return New VerifierResult(isOk)
End Function
Creating a custom verifier attribute for your custom verifier
The easiest way to create your own custom attribute is to inherit from one of our pre-defined
verifier attribute classes. Below is an example of inheriting from a
PropertyValueVerifierAttribute class by extending the NotEmptyGuidVerifier above.
C#
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = false)]
public class NotEmptyGuidVerifierAttribute : PropertyValueVerifierAttribute {
protected override Verifier BuildVerifierCore(Type pType, String propertyName) {
return new NotEmptyGuidVerifier(pType, propertyName);
}
}
VB
<AttributeUsage(AttributeTargets.[Property] Or AttributeTargets.Field, Inherited := False)> _
Public Class NotEmptyGuidVerifierAttribute Inherits PropertyValueVerifierAttribute
Protected Overrides Function BuildVerifierCore(pType As Type, propertyName As String) As
Verifier
Return New NotEmptyGuidVerifier(pType, propertyName)
End Function
End Class
You can then apply the attribute to the fields in your buddy class.
C#
public class CustomerMetadata {
[NotEmptyGuidVerifier]
public static Guid CustomerID;
}
VB
Public Class CustomerMetadata
<NotEmptyGuidVerifier> _
Public Shared CustomerID As Guid
End Class

Configure a verifier
Much of the work involved in configuring a verifier is performed via the VerifierOptions
class. This class collects a number of settings that affect a verifiers behavior, such as when it
it is run and how it handles exceptions. An instance of the type is available as a property on
the VerifierEngine class via the DefaultVerifierOptions; property and also on the Verifier,
VerifierArgs, and VerifierResults classes as the VerifierOptions property. VerifierOptions are
"inherited" or "defaulted" from the VerifierEngine down to all of a VerifierEngine's Verifiers
and VerifierArgs and finally to the VerifierResults of each Verifier. This will be described in
more detail later.


Properties of the VerifierOptions class

Property Description Type System Default Value
ExecutionModes
Gets or sets the
conditions
under which
which a verifier
is executed. See
the material
immediately
below the table
for more
information
about these.
Enum
VerifierExecutionModes.InstanceAndOnBefor
eSetTriggers
ErrorNotificationMode
Used to
determine
whether the
Entity should
throw errors
during a
property
Enum VerifierErrorNotificationMode.Notify
verification or
raise the errors
thru the
INotifyDataErro
rInfo interface
instead.
ShouldExitOnBeforeSetE
rror
Whether or not
to perform the
'set' of a
proposed value
when an error
occurs. Note
that this setting
is only
applicable with
'BeforeSet'
ExecutionMode
s.
Boolean false
ErrorContinuationMode
Gets or sets
whether a
failure in this
verifier should
stop the
execution of
the remainder
of the batch in
which this
verifier is
executing
Enum VerifierErrorContinuationMode.Continue
TreatWarningsAsErrors
Whether to
treat warnings
as errors
Boolean false
ShouldTreatEmptyString
AsNull
For required
value
validation, this
determines
whether empty
strings are
treated as if
they were null.
Boolean true
RawVerifierOptions
A version of this
same
VerifierOptions
instance
without
"inheritence"
interpretation.
May be used to
determine
which
properties are
actually
inherited
VerifierOpti
ons
N/A
The system default values shown in the table above are the default settings for the properties
of DefaultVerifierOptions.
All VerifierOptions properties can be inherited from a parent class and, by default, do so. A
VerifierEngine is parent to any Verifiers contained within it; A Verifier, in turn, is parent to
any VerifierResults resulting from its execution.
By default, every verifier is created with a VerifierOptions instance is created with every
property conceptually set to inherit its vaoue from its parent as described below:
All of enum-valued property types on VerifierOptions (VerifierExecutionModes,
VerifierErrorNotificationMode and VerifierErrorContinuationMode) each have a special
Inherit enumeration value that may be used to indicate inheritance from a parent. Properties
that are of type bool? (nullable booleans) may be set to null to accomplish the same result.
This means that if any property on a VerifierEngine's DefaultVerifierOptions is changed, then
by default, every Verifier and VerifierResult will inherit this change. And since Verifier and
VerifierResult have their own VerifierOptions property, any aspect of VerifierOptions can be
overwritten ( changed from 'Inherit' to another value) for any given Verifier or VerifierResult.
Any property value returned from a VerifierOption instance will be the "interpreted" value.
This means that if a value is inherited from a parent you will see the parent's value ( and it's
parent's value if necessary). Therefore if you set one of the VerifierOption's properties to
"Inherit" and then read the value back you will get the actual inherited value.
If you need to know whether a value is inherited as opposed to having been actually set on a
VerifierOption's instance, the RawVerifierOptions property described below may be used.
Since the VerifierEngine.DefaultVerifierOptions property is the root parent for all
VerifierOptions instances, it will not allow "Inherit" to be set on any of its properties.
ExecutionModes
The determination of when and how a verifier is executed is controlled via the
IdeaBlade.Validation.VerifierOptions.ExecutionModes and
IdeaBlade.Validation.Verifier.TriggerLinks properties on each verifier. A verifier can be
executed either
1. in response to a single change (e.g., of a property value); or
2. in the context of validating an entire object.
The first type of validation listed above is known as a property value validation. The second
is known as an instance validation.
We would apply a property value validation when (for example) a user was changing, or had
just changed, the HireDate on an employee. At that time we would only want to run those
validation tests whose outcome we feel may have been affected by this specific change. Our
goal would be to provide the end user with instant feedback about their change. In most cases,
it will never be easier for them to correct a mistake than immediately after making it!
Property value validations can be subdivided into before and after categories. A BeforeSet
validation is applied before a proposed new property value is actually pushed into the
business object. This can be used to prevent invalid data from ever getting into the business
object. An AfterSet validation is applied after the new value is pushed into the business object.
The ShouldExitOnBeforeSetError and ErrorNotificationMode properties described later can
be used to control further details involving a property value validation.
Instance validation describes an operation that completely validates an entire entity, applying
all relevant validation rules, whether those rules apply to individual properties of that entity,
to a combination of its properties (the validity of whose values must be assessed in relation to
each other), or in some other way to the entity as a whole.
We might perform an instance validation, for example, on a particular instance of an
Employee before permitting it to be saved to the database. This would likely require
performing validation tests on a number of individual properties of the employee object; it
might also require testing the state of related objects (such as the Orders written by that
Employee). Only if the entire suite of tests required to fully validate the Employee were
passed would we give the okay to save it to the database.
Note that instance validation would be unnecessary if we could really be sure that every
change affecting our Employee would be addressed by an appropriate set of property value
validations. In practice this can be very difficult, or even impossible, to ensure. What if, for
example, our Employee is changed by some other application which doesnt apply the same
rules that our does? What if it is changed directly in the database by someone with access to
that? Even when we can guarantee that neither of those things happen, the mechanisms by
which a given entity can be changed inside a single application can become quite complex
over time. For all of those reasons, developers commonly perform instance validation at such
key junctures as when an entity is submitted for saving. Its an important last line of defense
against invalid data.
It is common for a given verifier to be applicable during instance validation as well as during
property value validation. Every verifier comes with information about the situations in which
it should be executed, via its VerifierOptions.ExecutionModes property. That property takes
values from a VerifierExecutionModes enumeration whose choices permit you to make your
verifier run in any and all of the circumstances you deem appropriate. The values in the
VerifierExecutionModes enumeration, and their impacts, are as follows:
Enum value Description
Instance Run during instance validation.
OnBeforeSetTriggers
Run in response to designated triggers, before the proposed value
has been pushed into the business object.
OnAfterSetTriggers
Run in response to designated triggers, after the proposed value
has been pushed into the business object.
InstanceAndOnBeforeSetTriggers
Run during instance validation and in response to designated
triggers (usually property value changes), before the proposed
value is pushed into the business object.
InstanceAndOnAfterSetTriggers
Run during instance validation and in response to designated
triggers (usually property value changes), after the proposed
value has been pushed into the business object.
All
Run during instance verification and in response to designated
triggers (both before the proposed value is pushed into the
business object, and also after it has been pushed into the
business object).
Disabled Do not run.
Inherit
Inherit the ExecutionModes setting from the types parent
(Verifier if a VerifierResult, and VerifierEngine if a Verifier).
Settings of InstanceAndOnBeforeSetTriggers and InstanceAndOnAfterSetTriggersare by far
this most common (after Inherit). All is a particularly uncommon setting because it orders
triggered execution both before and immediately after a new value is pushed into a business
object. However, a verifier, as it so happens, has access to information about the triggering
context in which it is being run (i.e., before or after), so it is possible to include within a single
verifier logic that will only be applied in one context or another. From this arises the
possibility that you, the developer, might want such a verifier to run in both triggering
contexts.
BeforeSet Versus AfterSet Execution
This topic deserves special discussion, as the choice between these two execution modes can
be difficult.
All other things being equal, it is desirable never to allow invalid values into a business object
in the first place. If all things were equal, one would use OnBeforeSetTriggers or
InstanceAndOnBeforeSetTriggers as the ExecutionModes for all property-level verifiers.
However, in practice, these settings can cause problems, especially before an application has
been fully fleshed out. For example, in the user interface, a BeforeSet verifier can demand that
the end user fix a bad value entered for a property right then and there, before moving on to
any other work -- even if she hasnt the faintest idea what to change the bad value to. [Note
that this will NOT occur where the ErrorNotificationMode is set to Notify ( the default).] In
such as case, in order to handle such issues in a manner thats friendly to the end user then
you may want to use VerifierExecutionModes.InstanceAndOnAfterSetTriggers.
ErrorNotificationMode
Regardless of whether validation is performed before or after a property is set, the next issue
deals with how to handle any validation errors. The VerifierErrorNotificationMode
enumeration offers the following choices:
Enum value Description
Notify
Causes notification through the INotifyDataErrorInfo and IDataErrorInfo
interfaces.
ThrowException Throws an exception.
NotifyAndThrowException
Notify using INotifyDataErrorInfo and IDataErrorInfo interfaces and then
throw an exception.
Inherit Inherit the ErrorNotificatioMode from the parent.
Basically, there are two choices, either make use of the
INotifyDataErrorInfo/IDataErrorInfo interfaces or throw an exception. A third choice, that
of doing both, is available but is rarely used. We tend to recommend going with the use of
notification interfaces, although there are use cases where throwing an exception makes a
good deal of sense. You can even mix and match with some verifiers set up one way and
others another way.
ShouldExitOnBeforeSetError
In the event that one of the "BeforeSet" ErrorNotificationModes is selected AND you
have an ErrorNotificatioMode of Notify, you have one further choice:
Do you want the property setter to exit before actually setting the value in the case of a
validation error?
Note that exiting simply means that the property never gets set, but no error is thrown. This
can be very handy, if you want to insure that "bad" values never make it into your entity but at
the same time you really want to use notification semantics and don't want any errors thrown
within your property setters.
Setting this value to null (Nothing in VB) is the equivalent of setting any of the enumerated
values to "Inherit".
ErrorContinuationMode
Within an instance validation, many individual verifiers may need to be executed in
sequence. The ErrorContinuationMode allows any individual validation to stop the process.
This is often desirable if we know that the failure (or success) of one validation means that we
can short-circuit the need for further validations of the instance. The ErrorContinuationMode
enumeration consists of the following values:
Enum
value
Description
Stop Stop any further verifier execution within this batch if an error is encountered.
Continue
Continue executing other verifiers in this batch even if an error is encountered (the
default).
Inherit Inherit the ErrorContinuationMode from the parent.
TreatWarningsAsErrors
The execution of any verifier results in a VerifierResult instance. Each VerifierResult has a
VerifierResultCode that describes the type of the result. Setting the TreatWarningsAsErrors to
true, will cause any VerifierResults with a VerifierResultCode of OkWarning to be treated as
validation errors.
ShouldTreatEmptyStringAsNull
The ShouldTreatEmptyStringAsNull property is only applicable in the context of a string
length and required value validations. The idea is to provide the developer with the ability to
consider an "Empty string" as a null for the purposes of performing required value
validations. This is usually a good practice, because it is very difficult for a user of an
application to "see" the difference in a text box between a null value and an empty string, and
having an empty string pass validation whereas a null value fails it can be very confusing.
RawVerifierOptions
An "uninterpreted" version of any VerifierOptions instance is available via the
RawVerifierOptions property. The version returned by this property will not perform any
interpretation of the property values, so you may use this version to determine whether any
given property is actually inherited or not.
Discover verifiers
A VerifierEngine is both a container and an execution engine for verifiers. Verifier instances
are added to each engine either via a discovery process or programmatically.


Verifier discovery
The VerifierEngine lazily discovers verifiers in the types it is asked to verify. Note: automatic
discovery is not always a good thing, and developers can disable an engines automatic
discovery. An engine with automatic discovery disabled can still perform discovery when
asked to do so.
When a VerifierEngine attempts to verify an instance of a type it has not seen before, it probes
the type reflectively, looking for verifiers defined for the type and its base types.
The probing strategy is as follows.
1. Look for instances of the VerifierAttribute. DevForce provides a number of common verifiers
in attribute form all of which descend from VerifierAttribute. The developer can also add
custom VerifierAttribute subclasses just as he can add custom Verifiers. These define the
attributed verifiers. In Silverlight applications, .NET ValidationAttributes will also be
discovered.
2. Look for VerifierAttributes on the members of the metadata "buddy" class defined for the
type
3. Look for any implementations of the IVerifierProvider interface, and call the GetVerifiers
method of each.
We have seen the attribute verifiers earlier.
A VerifierProvider might look like the following:
C#
/// <summary>
/// Implement IVerifierProvider interface to give DevForce
/// the verifiers in use at run time.
/// </summary>
public class VerifierProvider : IVerifierProvider {

public IEnumerable<Verifier> GetVerifiers(
object verifierProviderContext) {
List<Verifier> verifiers = new List<Verifier>();
verifiers.Add(GetHireDateRangeVerifier());
verifiers.Add(new BirthDateRangeVerifier());
verifiers.Add(GetBornBeforeHiredVerifier());
verifiers.Add(GetPhoneNumberVerifier(Employee.PropertyMetadata.HomePhone));
return verifiers;
}
}
VB
''' <summary>
''' Implement IVerifierProvider interface to give DevForce
''' the verifiers in use at run time.
''' </summary>
Public Class VerifierProvider
Implements IVerifierProvider

Public Function GetVerifiers(ByVal verifierProviderContext _
As Object) As IEnumerable(Of Verifier)
Dim verifiers As New List(Of Verifier)()
verifiers.Add(GetHireDateRangeVerifier())
verifiers.Add(new BirthDateRangeVerifier())
verifiers.Add(GetBornBeforeHiredVerifier())
verifiers.Add(GetPhoneNumberVerifier(Employee.PropertyMetadata.HomePhone))
Return verifiers
End Function
End Class
The class that implements the IVerifierProvider must have an empty public constructor. The
reason for this is that DevForce will internally create an instance of this type and call its
GetVerifiers method. For this reason it is usually a good idea to have your IVerifierProvider
implementation be a completely separate class, so that you will not be tempted to remove the
public constructor for other reasons.
Adding or removing a verifier programmatically
Verifiers can be also added or removed from a VerifierEngine by calling its AddVerifier and
RemoveVerifier methods. Verifiers can be added or removed from a VerifierEngine at any
time.
The engine raises a VerifiersChanged event whenever verifiers are added or removed. This
event will inform any subscriber of the addition or removal of any verifier. Note that the event
is also raised when triggers are added or removed from a verifier that has previously been
registered in the engine.
Perform a validation
In most cases, you will want to perform validation either when a property on one of your
entities is set, or as part of a comprehensive validation of an object instance.


Property level validation

Property level validations should be run whenever the value of some property on an entity is
set and that property has a verifier or verifiers associated with it. For a DevForce entity, this
occurs automatically because internally DevForce calls either
VerifierEngine.ExecuteBeforeSet or VerifierEngine.ExecuteAfterSet whenever a property is
set. Which one is called is determined by the VerifierExecutionModes settings on each
verifier. This occurs during the execution of the autogenerated call to the
EntityProperty.SetValue method; an autogenerated code fragment is shown below:
C#
...
public string CompanyName {
get { ... }
set { PropertyMetadata.CompanyName.SetValue(this, value); }
}
VB
Public Property CompanyName() As String
Get
...
End Get
Set(ByVal value As String)
PropertyMetadata.CompanyName.SetValue(Me, value)
End Set
End Property
This means that you will NOT have to write ANY code to perform property level validations on any
DevForce generated entity type.
If you are working with a custom property or an object type that is not a DevForce entity, you
will need to write some of this scaffolding behavior yourself. For example:
C#
public String ShortName {
get { return _shortName; }
set {
VerifierResultCollection verifierResults = _verifierEngine.ExecuteBeforeSet(this, "ShortName",
value);
if (verifierResults.Ok) {
_shortName = value;
} else {
// Handle verifierResults here
}
}
}
}
VB
Public Property ShortName() As String
Get
Return _shortName
End Get
Set(ByVal value As String)
Dim verifierResults As VerifierResultCollection = __
verifierEngine.ExecuteBeforeSet(Me, "ShortName", value)
If verifierResults.Ok Then
_shortName = value
Else
' Handle verifierResults here
End If
End Set
End Property
Note that the ExecuteBeforeSet method above takes an object instance, a property name and a
proposed value; the result is a VerifierResultCollection that contains a collection of individual
VerifierResults as well as an aggregate Ok property. We have also assumed in the example
above the availability of a VerifierEngine instance; _verifierEngine.
DevForce actually does something a good deal more complex under the covers, because it
calls both the ExecuteBeforeSet for 'beforeSet' verifiers and ExecuteAfterSet for 'afterSet'
verifiers and interprets and handles verifier results in accordance with the VerifierOptions
property of each verifier. Relevant VerifierOptions properties include ErrorNotificationMode,
ErrorContinuationMode, TreatWarningsAsErrors and ShouldExitOnBeforeSetError.
Instance level validation

Instance validation is much like property level validation except that you call the
VerifierEngine's Executemethod instead of the ExecuteBeforeSet or ExecuteAfterSet
methods. As with those methods, Execute also returns a VerifierResultCollection, whose
individual members are each a VerifierResult.
C# VerifierResultCollection aVerifierResultCollection = _verifierEngine.Execute(anEmployee);
VB Dim aVerifierResultCollection As VerifierResultCollection =
_verifierEngine.Execute(anEmployee){{/code}}
Instance validation is called automatically by DevForce on the EntityServer just prior to the
execution of a save, but most developers will want to call it programmatically in client side
code as well.
It is also possible to execute on demand a specified collection of verifiers, or a single verifier:
C#
Verifier birthDateVerifer = aVerifierEngine.GetVerifier(
typeof(Employee), typeof(DateTimeRangeVerifier),
Employee.EntityPropertyNames.BirthDate);
aVerifierResultCollection = aVerifierEngine.Execute(anEmployee,
new List<Verifier>() { birthDateVerifer }, null);
VB
Dim birthDateVerifer As Verifier = aVerifierEngine.GetVerifier(GetType(Employee), GetType _
(DateTimeRangeVerifier), Employee.EntityPropertyNames.BirthDate)
aVerifierResultCollection = aVerifierEngine.Execute(anEmployee, New List _
(Of Verifier)() From {birthDateVerifer}, Nothing)
However, this is unlikely to be a common operation in your application.
Examine the validation results

You can examine a collection of VerifiersResults. Each VerifierResult consists of the
following readonly properties:
Property Property Type Description
ResultCode VerifierResultCode
A classification of the result of this validation, primarily a
classification of the type of the success or failure of the
operation.
Message String A description of the result.
Verifier Verifier
The verifier that this VerifierResult resulted from. This will be
null (Nothing in VB) if this is a "remote" VerifierResult.
TargetInstance Object The object instance that was validated to get this result.
VerifierOptions VerifierOptions
The VerifierOptions on the Verifier that was executed to get this
result
VerifierContext VerifierContext
The VerifierContext under which this validation was run. This
will be null (Nothing in VB) if this is a "remote" VerifierResult.
TriggerContext TriggerContext
The TriggerContext under which this validation was run. The
TriggerContext contains information about the timing
(BeforeSet, AfterSet) of the validation among other things.
PropertyNames ICollection<String> List of names of properties involved in this validation.
The VerifierResultCodeenumeration consist of the following values:
Value Description
Ok Was this a successful validation.
Error Was this a failed validation.
OkWarning
Was this is a "warning" result. Whether this is treated as a success or failure
depends on the VerifierOptions.ShouldTreatWarningsAsErrors flag.
OkNotApplicable
Whether this result occured because the validation was not applicable to the
data;
ErrorInsufficientData Whether this result occured because of insufficient data.
The following methods on the VerifierResult class provide a shorthand mechanism for
accessing the actual enumerated values shown above:
Method
Success
or
Failure
Description
IsOk Success Was this a successful validation.
IsError Failure Was this a failed validation.
IsWarning Either
Was this is a "warning" result. Whether this is treated as a success or
failure depends on the VerifierOptions.ShouldTreatWarningsAsErrors
flag.
IsNotApplicable Success
Whether this result occured because the validation was not applicable to
the data;
IsInsufficientData Failure Whether this result occured because of insufficient data.
So for example the following two expressions mean the same thing:
C#
ValidationResultCode vrc = ...
var isError = (vrc == ValidationResultCode.Error);
// is same as
var isError = vrc.IsError();
VB
Dim vrc As ValidationResultCode =...var isError = (vrc Is ValidationResultCode.Error)
' is same as
Dim isError = vrc.IsError()
Note that both the Verifier and the VerifierContext properties will be null for any
VerifierResult that occurs as a part of a "remote" validation. A "remote" validation is one
where the validation occurs on the EntityServer instead of on the client. This is because, in
such validations, the Verifier and its VerifierContext only exist on the EntityServer and we
may not want these verifiers to be accessible to the client. In this case, we only want the
results of the validation.
Example
The following code, for example, iterates through a collection of VerifierResults, captures the
Message property value of each one that represents an error. (Note that a Verifier always
returns a VerifierResult when executed, regardless of whether an error was found.)
C#
bool foundErrors = false;
foreach (VerifierResult aVerifierResult in aVerifierResultCollection) {
if (aVerifierResult.IsError) {
foundErrors = true;
_localOutput.Append(string.Format("\tValidation Failure: {0}\n",
aVerifierResult.Message));
}
}
VB
Dim foundErrors As Boolean = False
For Each aVerifierResult As VerifierResult In aVerifierResultCollection
If aVerifierResult.IsError Then
foundErrors = True
_localOutput.Append(String.Format(vbTab & _
"Validation Failure: {0}" & vbLf, aVerifierResult.Message))
End If
Next aVerifierResult

Intercept a validation
The ability to intercept a validation chain while it is executing and possibly change
validation behaviors and/or results is a suprisingly common requirement. To accomplish this
DevForce provides a pluggable delegate that, if defined, will be called after the execution of
each verifier within the validation chain. This is called a VerifierBatchInterceptor .


A BatchInterceptor property is defined on the VerifierBatchInterceptor.
C# public virtual VerifierBatchInterceptor BatchInterceptor { get; set; }
VB Public Overridable Property BatchInterceptor() As VerifierBatchInterceptor
The VerifierBatchInterceptor delegate is defined as:
C#
public delegate VerifierErrorContinuationMode VerifierBatchInterceptor(
object instance,
TriggerContext triggerContext,
VerifierContext verifierContext
)
VB
Public Delegate Function VerifierBatchInterceptor( _
ByVal instance As Object, ByVal triggerContext As TriggerContext, _
ByVal verifierContext As VerifierContext) As _
VerifierErrorContinuationMode _
Implements VerifierEngine.VerifierBatchInterceptor
with the following VerifierErrorContinuationMode enum values:
Value Description
Stop Stop executing, any verifiers further down the chain will be skipped.
Continue Continue executing
Inherit (See VerifierOptions inheritance discussion)
Interception via the BatchInterceptor can be used to decide whether to continue with the
current verification batch or to stop and return to the point in the program where the
validation was triggered. The interception delegate also allows the currently executing
validation's VerifierResultCollection to be modified. In other words, additional VerifierResults
can be added or removed or summarized into a smaller number of VerifierResults after each
verifier within the batch executes.
One example of its possible uses is to stop the verification process when the verification
results already contains more than a maximum number of errors.
The following code sample below shows how you would create and use an interceptor.
C#
public static VerifierErrorContinuationMode
EmployeeBatchInterceptor(Object instance, TriggerContext
triggerContext, VerifierContext verifierContext) {
if (verifierContext.VerifierResults.Errors.Count > 10) {
verifierContext.VerifierResults.Add(
new VerifierResult(false,
"Too many errors, stop immediately"));
return VerifierErrorContinuationMode.Stop;
} else {
return VerifierErrorContinuationMode.Continue;
}
}

public void DoEmployeeBatchInterceptor() {
var mgr = new NorthwindIBEntityManager();
mgr.VerifierEngine.BatchInterceptor = EmployeeBatchInterceptor;
mgr.VerifierEngine.DefaultVerifierOptions.ExecutionModes =
VerifierExecutionModes.InstanceAndOnAfterSetTriggers;
mgr.VerifierEngine.DefaultVerifierOptions.ErrorNotificationMode =
VerifierErrorNotificationMode.Notify;
var employee = mgr.Employees.FirstOrNullEntity();
employee.BirthDate = DateTime.Today.AddYears(7);
//Verification batch will be executed here
var results = mgr.VerifierEngine.Execute(employee);
_localOutput.Append(results.Errors.Last().Message);
}
VB
Public Shared Function EmployeeBatchInterceptor( _
ByVal instance As Object, ByVal triggerContext_Renamed As _
TriggerContext, ByVal verifierContext_Renamed As VerifierContext) _
As VerifierErrorContinuationMode
If verifierContext_Renamed.VerifierResults.Errors.Count > 10 Then
verifierContext_Renamed.VerifierResults.Add( _
New VerifierResult(False, "Too many errors, stop immediately"))
Return VerifierErrorContinuationMode.Stop
Else
Return VerifierErrorContinuationMode.Continue
End If
End Function

Public Sub DoEmployeeBatchInterceptor()
Dim mgr = New NorthwindIBEntityManager()
mgr.VerifierEngine.BatchInterceptor = _
AddressOf EmployeeBatchInterceptor
mgr.VerifierEngine.DefaultVerifierOptions.ExecutionModes = _
VerifierExecutionModes.InstanceAndOnAfterSetTriggers
mgr.VerifierEngine.DefaultVerifierOptions.ErrorNotificationMode _
= VerifierErrorNotificationMode.Notify
Dim employee = mgr.Employees.FirstOrNullEntity()
employee.BirthDate = Date.Today.AddYears(7)
'Verification batch will be executed here
Dim results = mgr.VerifierEngine.Execute(employee)
_localOutput.Append(results.Errors.Last().Message)
End Sub
VerifierContext.EndOfBatch
In addition to being fired after each verifier, the BatchInterceptor is also fired at the very end
of the current verification batch. This is to provide useful behavior such as analyzing the
results of the verification batch. Below is an example of the EmployeeBatchInterceptor
delegate above modified by adding a simple logic using the VerifierContext.EndOfBatch
property. The logic adds a new VerifierResult to the VerifierResultsCollection with a
VerifierResultCode.Error and a string message to indicate how many total errors are
accumulated at the end of batch.
C#
public static VerifierErrorContinuationMode EmployeeBatchInterceptor(
Object instance, TriggerContext triggerContext,
VerifierContext verifierContext) {

if (verifierContext.EndOfBatch) {
verifierContext.VerifierResults.Add(
new VerifierResult(VerifierResultCode.Error,
String.Format("Accumulated a total of {0} error(s)",
verifierContext.VerifierResults.Errors.Count)));
return VerifierErrorContinuationMode.Stop;
} else {
if (verifierContext.VerifierResults.Errors.Count > 3) {
verifierContext.VerifierResults.Add(new VerifierResult(
VerifierResultCode.Error,
"Too many errors, stop verification immediately"));
return VerifierErrorContinuationMode.Stop;
} else {
return VerifierErrorContinuationMode.Continue;
}
}
}
VB
Public Shared Function EmployeeBatchInterceptor(ByVal instance _
As Object, ByVal triggerContext_Renamed As TriggerContext, _
ByVal verifierContext_Renamed As VerifierContext) As _
VerifierErrorContinuationMode

If verifierContext_Renamed.EndOfBatch Then
verifierContext_Renamed.VerifierResults.Add( _
New VerifierResult(VerifierResultCode.Error, _
String.Format("Accumulated a total of {0} error(s)", _
verifierContext_Renamed.VerifierResults.Errors.Count)))
Return VerifierErrorContinuationMode.Stop
Else
If verifierContext_Renamed.VerifierResults.Errors.Count > 3 Then
verifierContext_Renamed.VerifierResults.Add( _
New VerifierResult(VerifierResultCode.Error, _
"Too many errors, stop verification immediately"))
Return VerifierErrorContinuationMode.Stop
Else
Return VerifierErrorContinuationMode.Continue
End If
End If
End Function

Display validation results
Now that the application is detecting invalid data and throwing exceptions, we had better
think about how we want to handle those exceptions and tell the user what is going on.
Verification with a Silverlight UI
System.ComponentModel.INotifyDataErrorInfo is a Silverlight-only interface that defines
members that data entity classes can implement to provide custom, asynchonous validation
support. Important Silverlight user interface controls including the DataForm and DataGrid
check for the implementation of this interface by data entities to which they are bound and
provide excellent messaging in the user interface to help end users learn about and correct
validation errors.
Such Silverlight user interface controls do not depend upon exceptions being thrown in order
to learn about validation problems. Instead, they subscribe to an ErrorChanged event
published by the entity as part of its INotifyDataErrorInfo compliance. That event is raised by
the data entity whenever it believes that a change to its state might be important to some
control in the user interface. The UI control, learning of such a change, can then query the
data entity via its INotifyDataErrorInfo.GetErrors() method to obtain a current set of
validation errors, which it may then expose to the end user as its developer sees fit.
Because of the support for INotifyDataErrorInfo by Silverlight UI controls, most developers
working in Silverlight will want to set the system default for
VerifierOptions.ErrorNotificationMode to Notify rather than any setting that results in
exceptions being thrown for validation errors.
Verification with a WPF UI
Currently there is no WPF equivalent of INotifyDataErrorInfo; and WPF user interface
controls typically rely upon exceptions as their mechanism for learning about validation errors
and stimulus to display information about them. Hence to accommodate WPF UI controls
most developers will want to set the system default for
VerifierOptions.ErrorNotificationMode to ThrowExceptions or NotifyAndThrowExceptions .
IdeaBlade.Core.INotifyDataErrorInfo
A IdeaBlade.Core.ComponentModel.INotifyDataErrorInfo interface has been implemented in
DevForce 2010 with the same semantics as the similarly named class in the Silverlight CLRs
version of System.ComponentModel. This interface is implemented by the DevForce
EntityWrapper, from which all of your DevForce-generated Entity types derive. Therefore all
DevForce-generated entities, Silverlight or otherwise, publish the ErrorsChanged event,
maintain a VerifierResultCollection, and provide a GetErrors method that returns the
collection of those. Because of the implementation of this interface by Entity, it is now
possible for you to configure your entities to collect validation errors rather than throw
exceptions. You may also do both, if you wish. Again, for most purposes,
VerifierOptions.ErrorNotificationMode should be set in Silverlight applications to notify but
not throw exceptions, and in WPF applications to throw exceptions (and, optionally, notify if
the developer wishes to use that capability for other reasons than interaction with the
commonly available UI controls).
A developer could choose, in a WPF application, to suppress exceptions and use the
INotifyDataErrorInfo notification facilities instead. To do that, however, she would have to
encode her UI explicitly so that it responds to the interfaces ErrorsChanged event, as the
commonly available WPF controls know nothing about any INotifyDataErrorInfo interface or
behavior.
The INotifyDataErrorInfo workflow
Here is the validation workflow that properly occurs when the facilities of
INotifyDataErrorInfo are in use (as is standard in Silverlight 4 applications):
1. The end user changes the value of a property.
2. Verifiers triggered by the changes to that property are fired.
3. Each verifier that is run causes the INotifyDataErrorInfo.ErrorsChanged event to be raised.
The event subscriber receives an ComponentModel.DataErrorsChangedEventArgs object that
includes the name of the property whose error state may have changed. If there is no
specific property whose error state may have changed, but yet the error state of the entity
taken as a whole may have changed, then the subscriber receives a null value in
ComponentModel.DataErrorsChangedEventArgs.PropertyName.
4. The control, which subscribes to the entitys INotifyDataErrorInfo.ErrorsChanged event
(standard in Silverlight only!), receives notification that a change has occurred which may
have affected the bound entitys error state. Said notification includes the name of the
specific property whose error state has potentially changed, if there is a specific property.
The control then calls INotifyDataErrorInfo.GetErrors() on the data entity, passing it the name
of the property (if there was one) to get current information about the error state (of that
property). GetErrors() returns a collection of VerifierResults. The UI then updates the
displayed information about the error state of the property and/or the entity.
A developer wishing to make a WPF UI respond the same way would have to code all of the
behaviors described in step 4 above.
Verification with a WinForm UI
Data binding in WinForms is much more primitive than in either WPF or Silverlight. As a
result, some of the processes described below are more complicated in this environment.
UI lockup
The UI is going to lock up the moment the user enters an invalid value into a verified UI
control. That is any data entry control: TextBox), DataPicker), ComboBox, etc. The user will
not be able to leave that control until she enters a value that passes validation not even to
close the form.
In this illustration, the user cleared the Last Name. The last name is required. The form
displays an error bullet and prevents the user from moving out of the textbox.

How does the user recover?
If this were a grid, she could press the [Esc] key; it is standard for grid controls to restore
the previous value when the user presses escape. How many users know that? In any case,
this TextBox is not in a grid and pressing [Esc] does nothing but ring an annoying bell.
The user can press the standard key chord for undo: Ctrl+Z. How many users know that?
No, the most users will just keep entering new values until they find one that lets them out of
the field.
Needless to say, a UI should apply the lock up enforcement technique sparingly. In the
authors opinion, it makes sense only for
a value the user must know and is sure to know
a value that must be correct immediately and at all times.
Dosage of a dangerous prescription drug would fit this bill. Few other properties qualify.
Unlock the UI with AutoValidate
Recall that the DevForce Entity.BeforeSetValue and Entity.AfterSetValue methods raise a
VerifierResultException when the property fails validation. This exception bubbles up and out
of the property setter.
Data binding traps the exception. During the data binding Validate event raised when the user
attempts to leave the TextBox. and responds by locking up the form. Fortunately, WinForms
.NET 2.0 makes it easy to change this response.
The key is the System.Windows.Forms.UserControl.AutoValidate property which takes one of
the System.Windows.Forms.AutoValidate enumerations.

AutoValidate Description
Inherit
Do what the parent UserControl does. The parent is the UserControl that
contains this UserControl.
This is the default for new UserControl instances.
If there is no parent, the value is the default,
EnablePreventFocusChange.
EnablePreventFocusChange
Prevents the user from leaving the control until the value passes
validation.
EnableAllowFocusChange
Validate but permit the user to leave the control if validation fails.
Disable
Does not validate. Generally not a good choice.
Inherit is the default value for all new UserControls
1
. Inherit means that the UserControl is governed by
the AutoValidate setting of its parent UserControls, the UserControl that contains it.
The outer UserControl, typically a Form, doesnt have a parent so it is governed by the
EnablePreventFocusChange setting.
If we never change the AutoValidate property on any UserControl, our application is governed by
the setting in the Form which, as we have seen, is EnablePreventFocusChange, the setting that locks
up the form. All UserControls within the Form are inheriting this behavior.
If we change the Forms AutoValidate property to EnableAllowFocusChange, the widgets on the Form
will no longer lock up when the setter throws an exception. Neither will widgets on the
contained UserControls because they inherit the parent Forms setting.
So the quick answer to UI lockup:
Change the Forms AutoValidate property to EnableAllowFocusChange
C# this.AutoValidate = System.Windows.Forms.AutoValidate.EnableAllowFocusChange;
VB me.AutoValidate = System.Windows.Forms.AutoValidate.EnableAllowFocusChange
Improving the users experience
EnableAllowFocusChange and BeforeSet triggers
AutoValidate.EnableAllowFocusChange works great for property verifiers governed by BeforeSet
triggers.
The user can move out of the TextBox. Yet she can still see the error bullet protesting the lack
of a last name.

The TextBox remains cleared so we can see that there is a problem or rather that there was a
problem, that our intent to clear the name was invalid.
The LastName property itself was never actually changed. A BeforeSet trigger prevents the
property setter from updating the object. At the moment there is a discrepancy between the
business object property value and the corresponding widget control display property on
screen
2
.
We can see reveal the discrepancy and cure it by scrolling off of the Nancy employee and
then returning to her. The TextBox refreshes with her current LastName property value which
remains Davolio.
EnableAllowFocusChange and AfterSet triggers
The behavior is different for verifiers evaluated in response to AfterSet triggers.
If we had a LastNameRequiredVerifier and set its ExecutionModes to InstanceAndOnAfterSetTriggers, the
LastName property value would be empty, just as it appears in the TextBox. A AfterSet trigger
causes validation after the property has been set with the proposed value.
We can confirm this by scrolling off of the Nancy employee and then returning to her. The
TextBox remains blank. The current LastName property value is empty.
However, we are no longer aware of the latent validation error. Our application does not
validate the Employee upon display and that might be a user experience problem
3
.
At least it is not a data integrity problem or doesnt have to be. We must assume that the
application follows our advice and ensures that every entity must survive instance
verification before it can be saved. We further assume that the application has some
mechanism to display errant entities and their problems. Perhaps a simple MessageBox will do.
This Employee will not survive validation, will not be saved, and the user will be told why.
Questionable user experience
This approach may be viable if little time can pass between data entry and instance
verification.
Some applications attempt a save whenever the user moves off the current screen. The user
will never lose sight of the LastName error bullet and the save effort will reveal all latent
problems with this employee.
Many applications delay save and allow the user to move around among entities with pending
changes. Thats how our tutorial works. Users can make a change to Nancy, scroll to
Andrew and make changes to him, then scroll back to Nancy to continue her updates.
In this kind of workflow, the user may not remember that there is a problem with the Nancy
object for minutes or hours. When the application finally tells the user about this problem, the
mental context is long gone and the application will be perceived to be unfriendly.
There is another, potentially greater risk. The user may make a critical business decision base
upon what is visible on the screen. That data could be in error. The user wont know it if she
scrolled off and then back on to the record.
If this risk is serious, the application must behave differently whenever the UI displays a new
object a new Employee in our example.
Instance verification upon display
One approach would be to perform instance verification whenever the currently displayed
object is changed.
1. ^ UserControl is the base class for developer designed screens. System.Windows.Form inherits from
UserControl. Individual UI widgets such as TextBox do not inherit from UserControl.
2. ^
3. ^ We could write code to perform instance validation whenever the Employee changed.
We could capture the VerifierResults and display them as well as light up bullets next to each
widget. The code is not hard to write but its not utterly trivial either. Well describe an
approach that achieves something of that effect using a different technique.
Validate on the server
By default, any changes submitted via an EntityManager.SaveChanges call will be validated
on the server as part of the save life cycle.. DevForce will automatically run instance
verification on each entity in the save list. If there are any validation errors an
EntityManagerSaveException is returned to the client. The FailureType on the exception will
be set to PersistenceFailure.Validation , and the error message will be a concatenation of all
validation error messages. The EntitiesWithErrors collection on the exception will also
contain all of the entities which failed validation. The EntityAspect.ValidationErrors property
on each of these entities will also return the validation errors. If you are binding to these
entities in your UI the validation error(s) are displayed as they would with local validation
failures (either on the property or instance).
Be sure to wrap a synchronous SaveChanges call in a try/catch, and if calling
SaveChangesAsync then be sure to call MarkErrorAsHandled to clear the error.
C#
var op = _mgr.SaveChangesAsync();
op.Completed += (o, args) => {
if (args.HasError) {
// If validation failed on server, mark as handled and let UI show errors.
if (args.Exception.FailureType == PersistenceFailure.Validation) {
args.MarkErrorAsHandled();
}
// Check other save errors too.
}
}
VB
Dim op = _mgr.SaveChangesAsync()
AddHandler op.Completed, Sub(o, args)
If args.HasError Then
' If validation failed on server,
' mark as handled and let UI show errors.
If args.Exception.FailureType = PersistenceFailure.Validation Then
args.MarkErrorAsHandled()
End If
' Check other save errors too.
End If
End Sub
Server validation is performed by the EntityServerSaveInterceptor, which you can sub-type to
customize save processing. The default VerifierEngine used is a single instance of a thread
safe "concurrent" VerifierEngine. Verifiers are discovered and added to the server-side
engine in the same way as they are in the client application, but it is not required that the same
verifiers be defined on both client and server. In this way you can define verifiers which will
only be executed on the client, or only executed on the server. To modify server-side
validation, sub-class the EntityServerSaveInterceptor and override the ValidateSave virtual
method.
Localize error messages
Last modified on March 22, 2011 16:28
Every verifier has a VerifierErrorMessageInfo property which in turn has a ResourceName
property. This name is automatically generated (and set) during code generation for attribute
based verifiers. For example, note the autogenerated ErrorMessageResourceNames on these
attributes:
C#
[StringLengthVerifier(MaxValue=15, IsRequired=false,
ErrorMessageResourceName="Employee_Country")]
public string Country {}
[RequiredValueVerifier(ErrorMessageResourceName="OrderDetail_Quantity")]
public short Quantity {}
VB
<StringLengthVerifier(MaxValue:=15, IsRequired:=False,
ErrorMessageResourceName:="Employee_Country")> _
Public ReadOnly Property Country() As String
End Property
<RequiredValueVerifier(ErrorMessageResourceName:="OrderDetail_Quantity")> _
Public ReadOnly Property Quantity() As Short
End Property
This resource name can also be set programmatically for any verifier defined in code.
The VerifierEngine has an ErrorsResourceManager property that can assigned to like this:
C# verifierEngine.ErrorsResourceManager = MyErrorMessages.ResourceManager;
VB verifierEngine.ErrorsResourceManager = MyErrorMessages.ResourceManager
where MyErrorMessages is the name of the strongly typed Designer.cs class generated by the
.NET ResX editor. The VerifierEngine will look up each verifier's ResourceName in the
registered ErrorsResourceManager in order to generate validation error messages.
Regarding localization of these resources, please see Microsofts documentation for more
information on this topic.
The VerifierEngine has a fallback ResourceManager it uses for system default error
messages. These resource names may be overridden in the programmatically specified
ResourceManager. The fallback manager ResX is shown below.
Most error messages contain substitution parameters; the meaning and order of these
substitution parameters is defined by the type of verifier involved. For example:
{0} is required.
{0} must be between {1} and {2} character(s).
By simply including {0}, {1}, and {2} in any message, you can easily determine what
parameters are used for that verifier.
Fallback ResourceManager ResX:
XML
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema

Version 2.0

The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.

Example:

... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader,
System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter,
System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a
comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-
microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing"
mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET
Framework object]</value>
<comment>This is a comment</comment>
</data>

There are any number of "resheader" rows that contain simple
name/value pairs.

Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.

The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:

Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.

mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"
msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0"
msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"
msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"
msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="VerifierAnd" xml:space="preserve">
<value>{0} and {1}</value>
</data>
<data name="VerifierBetween" xml:space="preserve">
<value>{0} must be between {1} and {2}</value>
</data>
<data name="VerifierBetweenDate" xml:space="preserve">
<value>{0} must be between {1:d} and {2:d}</value>
</data>
<data name="VerifierBetweenStringLength" xml:space="preserve">
<value>{0} must be between {1} and {2} character(s)</value>
</data>
<data name="VerifierInList" xml:space="preserve">
<value>Value must be among the valid choices for {0}</value>
</data>
<data name="VerifierMaxDate" xml:space="preserve">
<value>{0} must be on or before {1:d}</value>
</data>
<data name="VerifierMaxDateExclusive" xml:space="preserve">
<value>{0} must be before {1:d}</value>
</data>
<data name="VerifierMaxStringLength" xml:space="preserve">
<value>{0} cannot be longer than {1} characters(s)</value>
</data>
<data name="VerifierMaxValue" xml:space="preserve">
<value>{0} must be less than or equal to {1}</value>
</data>
<data name="VerifierMaxValueExclusive" xml:space="preserve">
<value>{0} must be less than {1}</value>
</data>
<data name="VerifierMinDate" xml:space="preserve">
<value>{0} must be on or after {1:d}</value>
</data>
<data name="VerifierMinDateExclusive" xml:space="preserve">
<value>{0} must be after {1:d}</value>
</data>
<data name="VerifierMinStringLength" xml:space="preserve">
<value>{0} cannot be shorter than {1} character(s)</value>
</data>
<data name="VerifierMinValue" xml:space="preserve">
<value>{0} must be greater than or equal to {1}</value>
</data>
<data name="VerifierMinValueExclusive" xml:space="preserve">
<value>{0} must be greater than {1}</value>
</data>
<data name="VerifierNotRequired" xml:space="preserve">
<value>{0} is not required</value>
</data>
<data name="VerifierRequired" xml:space="preserve">
<value>{0} is required</value>
</data>
<data name="VerifierValid" xml:space="preserve">
<value>{0} must be a valid {1}</value>
</data>
<data name="VerifierValidPattern" xml:space="preserve">
<value>{0} must be a valid {1} pattern</value>
</data>
</root>

Save
Last modified on March 23, 2011 23:36
If an application decides to save, it issues one of the overloads of
EntityManager.SaveChanges that can save an individual business object, an arbitrary list of
objects, or all entities with pending changes.
Saves are always transactional in DevForce.
Unmodified entities are never saved. Attempts to save them are ignored.
If concurrency checking is enabled, DevForce will confirm that entities being saved have not
been modified or deleted by another process since they were last retrieved.
The application can determine if a particular object is new, modified, marked for deletion, or
unmodified by examining its EntityState property which returns one of the corresponding
EntityState enumerations.
Initiation of any save operation causes the EntityManager to attempt to replace temporary ids
with permanent ids.
Add, change, and delete operations only affect entities in an EntityManager's entity cache.
They are not written to the data source nor are they visible to other application users until the
application tells the EntityManager to save them. Alternatively, the application can undo the
changes rather than save them.
Save-related topics elaborate on these points
Perform a save

Saving is the process of sending a collection of added, modified or deleted objects to some
backend datastore and having them be persisted there. The basics of performing a save are
described on this page. A description of the ways in which a save operation can be intercepted
or mediated will be discussed in subsequent pages.


Save API
In order to perform a save in DevForce, one of the following methods must be called.
Synchronous methods:
public SaveResult EntityManager.SaveChanges()
public SaveResult EntityManager.SaveChanges(SaveOptions saveOptions)
public SaveResult EntityManager.SaveChanges(IEnumerable entities, SaveOptions
saveOptions = null)
Asychronous methods:
public EntitySaveOperation EntityManager.SaveChangesAsync() {
public EntitySaveOperation EntityManager.SaveChangesAsync(Action<EntitySaveOperation>
userCallback, object userState = null)
public EntitySaveOperation EntityManager.SaveChangesAsync(SaveOptions saveOptions,
Action<EntitySaveOperation> userCallback = null, object userState = null)
public EntitySaveOperation EntityManager.SaveChangesAsyncIEnumerable entities,
SaveOptions saveOptions = null, Action<EntitySaveOperation> userCallback = null, object
userState = null)
Determining which entities to save
Two of the overloads shown above take a list of entities as the first argument. These versions
allow a developer to explicitly specify which entities to save. The overloads which do not take
a list of entities assume that all entities found in the EntityManager's cache that are marked as
either added, modified or deleted should be saved.
If either of the overloads specifying a list of entities is used, DevForce will perform an
additional check prior to sending these entities to the server. This check is to insure that if
any of the specified entities has a temporary id then every other entity that has a reference to
this id must also be in the save list. If this is not the case, DevForce will throw an exception,
with a description of which entities are causing a problem. Essentially, DevForce will not
allow a 'partial' save that could cause data corruption. This is not an issue when DevForce
determines which entities to save.
Saving a single entity
You'll notice that all SaveChanges methods will either accept an IEnumerable of entities or
will save all changes in the entity cache. This may at first seem confusing if you need to save
only a single entity. It's easy, though; just create a list, maybe a List<Entity>, and add the
changed entity to it. Or create an array on the fly, like so:
C# manager.SaveChanges(new[] { aChangedCustomer });
VB manager.SaveChanges(New () {aChangedCustomer})
The SaveOptions class
Every save performed by DevForce makes use of an instance of the SaveOptions class. This
instance is provided either by passing it into the SaveChanges call or by using value of the
EntityManager's DefaultSaveOptions property. Note that several of the overloads above take
a SaveOptions argument, those that do not make use of the
EntityManager.DefaultSaveOptions. The EntityManager.DefaultSaveOptions property can be
modified at any time to change these defaults.
Most of the time the default values for SaveOptions are sufficient and there is no need to use one of
the SaveChanges overloads that takes a SaveOptions parameter.
The SaveOptions class has several interesting properties:
Property PropertyType
Access

Description
TransactionSettings
TransactionSetti
ngs
get
set
Gets or sets the transactional behavior
for the save. This property is described
in more detail here: save-transactions.
Tag Object
get
set
Used to pass custom user
information to the entityserver
regarding the save operation.
This property can be very useful in
controlling the behavior of an
EntityServerSaveInterceptor. The
value of the SaveOptions property,
including this tag, is passed to each
instance of the
EntityServerSaveInterceptor during
its construction.
The value of this property must be
serializable by WCF.
The default value for this property
is null (Nothing in VB).
FixupTempIds FixupTempIds
get
set
Gets or sets the option to fixup all
generated temporary Ids or only
those Ids corresponding to entities
passed into the SaveChanges
method. Possible values are
FixupTempIds.All
Default
setting.
Perform Id
fixup on all
generated
temporary
Ids.
FixupTempIds.InSaveList
Only
Perform Id
fixup only
on those
entities
passed
into the
SaveChang
es
method.
This property is only relevant when
a SaveChanges call is made that
takes a collection of entities.
EntityTypesExcludedFromPostSaveR
efetch
IList<Type>
get
set
Gets or sets the types of entities to
be excluded from the refetch that is
performed after a save.
By default all entity types will be
refetched after a save, this setting
allows a developer to improve
performance by telling DevForce
which types cannot 'change' as a
result of the save and where a
refetch is therefore unnecessary.
PocoSaveMode PocoSaveMode
get Determines how to discover any
set custom server side POCO save
methods.
and one useful method:
Method Signature Description
public SaveOptions
WithTag(Object tag)
Used to create a clone of this SaveOptions but with the "Tag" set
to the specified value.
The SaveResult class
The synchronous SaveChanges calls return a SaveResult while the SaveChangesAsync
versions all return an EntitySaveOperation which contains a SaveResult property.
The SaveResult type contains the following properties:
Property PropertyType
Access

Description
Ok bool get
Returns whether or not the save
succeeded.
This will be true, unless the Save was
either canceled or had an exception that
was 'handled'.
SaveStatus SaveStatus get
Returns the kind of operation performed
during this save.
SaveStatus Description
Incomplete
The operation has not yet
completed.
NoOperation
There was nothing to
save, there were no
added, modified or
deleted entities to save (
and no many-many
relationship changes).
Cancelled
The operation was
cancelled either in a
Saving handler or in the
EntityServerSaveIntercept
or.
ExceptionHandl
ed
An exception was both
thrown and then handled
by an
EntityServerErrorIntercep
tor handler
Normal
The save completed
normally.

SavedEntities IList<Object> get List of entities that were saved.
WasCancelled bool get
Returns true if the save was canceled, either
during the Saving event or from within the
EntityServerSaveInterceptor.
WasExceptionHandl
ed
bool get
Returns true if an exception was thrown but
handled by an EntityServerError handler;
otherwise false.
HandledException
EntityManagerSaveExcepti
on
get
Returns the handled exception or null
(Nothing in VB) if no exception or
unhandled.
TemporaryIdMap UniqueIdMap get
Gets copy of the UniqueIdMap that was (or
would have been) used for fixup.
SaveResult.Ok returns "true" if the save was entirely successful. ( A SaveStatus of
NoOperation is still considered 'Ok').
If the save was canceled in a life-cycle handler, SaveResult.WasCancelled will return true
and SaveResult.Ok will return "false".
If the save threw an exception and was handled, SaveResult.WasErrorHandled will return
"true" and SaveResult.Ok will return "false".
If a save throws an exception and is not handled, no synchronous result will be returned at all
because an exception will have been thrown. If this occurs during an asynchronous call then
SaveResult.WasErrorHandled will be false and SaveResult.Ok will return "false".
After the Save
DevForce immediately re-queries all inserted or updated entities after saving them
successfully. This re-query is essential because the insert or update may provoke a data source
trigger that modifies the data source object. We often use a trigger to update an optimistic
concurrency column. A database-maintained timestamp is another common example. In such
cases, the row in the database is no longer exactly the same as the row we wrote.
The SaveOptions.EntityTypesExcludedFromPostSaveRefetch property ( mentioned above)
may be used to modify this behavior.
After the refetch the EntityServer sends the possibly 'updated' entity back to the clients
EntityManager. The revised entity is merged back into the cache, replacing the original and its
EntityState becomes Unchanged.
Perform a save asynchronously
DevForce provides asynchronous save functionality for two reasons:
Firstly, the Silverlight and WP7 CLR (common language runtime) environments do not permit
synchronous web service calls.
Secondly, even in those environments where synchronous API's are supported, there are use
cases where an asynchronous save can be useful.
While an overview of asynchonous programming in DevForce is also available; the remainder
of this topic discusses the specific asynchronous API's provided in the context of saving.


EntitySaveOperation and EntitySavedEventArgs
The return value from any call to one of the EntityManager.SaveChangesAsync overloads is
an instance of an EntitySaveOperation. 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 EntitySavedEventArgs parameter.
Regardless of whether you are working with an EntitySaveOperation or an
EntitySavedEventArgs, the following readonly properties are provided in addition to those
inherited from the BaseOperation or AsyncEventArgs base classes. Please see Asynchronous
Programming 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 save.
Property Property Type Description
Entities IList<Object> Returns the entities saved.
SaveResult SaveResult Returns the SaveResult - see SaveResult
Exception EntityManagerSaveException
Returns the exception thrown if an error occurred during
save processing.
Example
C#
// Using lambda syntax:
myEntityManager.SaveChangesAsync(op => {
var savedEntities = op.Entities;
var sr = op.SaveResult;
var error = op.Exception;
});

// Using Completed event syntax:
var op = myEntityManager.SaveChangesAsync()
op.Completed += (sender, eventArgs) => {
var savedEntities = eventArgs.Entities;
var sr = eventArgs.SaveResult;
var error = eventArgs.Exception;
};
VB
' Using lambda syntax:
myEntityManager.SaveChangesAsync(Sub(op)
Dim savedEntities = op.Entities
Dim sr = op.SaveResult
Dim err = op.Exception
End Sub)

' Using Completed event syntax:
AddHandler Dim op = myEntityManager.SaveChangesAsync() _
op.Completed, Sub(sender, eventArgs)
Dim savedEntities = eventArgs.Entities
Dim sr = eventArgs.SaveResult
Dim err = eventArgs.Exception
End Sub

Validate before a save
By default DevForce validates every entity on the server before saving it. This behavior
can be modified by overriding the ValidateSave method in a custom
EntityServerSaveInterceptor.
Client side validation is not performed automatically but can be easily accomplished via the
EntityManager.Saving event.


Handling validation errors
If any validation errors are encountered on the server, there are two mechanisms by which
these errors are reported back to the EntityManager that performed the save.
Any errors will be propagated back to the "errant" entities within the calling EntityManager's
cache and each of these entities will have its EntityAspect.ValidationErrors property
automatically updated. Providing that these entities have been 'bound' to a client side UI and
because of the eventing behavior provided by the ValidationErrors property and DevForce's
implementation of the INotifyDataErrorInfo and IDataErrorInfo interfaces; these errors
should appear immediately in the client side UI.
The EntityManagerSaveException.EntitiesWithErrors property of the
EntityManagerSaveException reported by the EntityManager.Saved event and the
EntitySaveOperation.Completed event, if the save call was asynchronous, will both contain
these 'errant entities'.
Any errors encountered can then be 'fixed' and the same save resubmitted again.
Handle save errors
The SaveResult returned by both synchronous and asynchronous SaveChanges calls provides
information which can help you handle save errors.


SaveResult.Ok returns "true" if the save was successful. If the save was canceled in a life-
cycle handler, SaveResult.WasCancelled will return "true" and SaveResult.Ok will return
"false".
If a save fails for any reason except 'Cancelation' an EntityManagerSaveException is
raised. For synchronous SaveChanges calls the exception is thrown, while in
SaveChangesAsync calls the exception is available on the EntitySaveOperation.
Handling the exception
You should prepare your code to trap and analyze the save exception. The
EntityManagerSaveException has the information you need to help diagnose and handle the
problem.
Always handle save exceptions.
Wrap every call to EntityManager.SaveChanges() in your own custom Save method.
Wrap every synchronous SaveChanges in a Try/Catch.
Add error logic to every asynchronous SaveChangesAsync to analyze the exception.
For asynchronous calls, remember to call MarkErrorAsHandled unless the application should
terminate.
Heres a code fragment showing a SaveAll method that matches our recommendation:
C#
internal void SaveAll() {
try {
MainEm.Manager.SaveChanges();// Save everything
DisplaySaveOk();
} catch (EntityManagerSaveException saveException) {
ProcessSaveFailure(saveException);
} catch {
throw; // re-throw unexpected exception
}
}
VB
Friend Sub SaveAll()
Try
MainEm.Manager.SaveChanges() ' Save everything
DisplaySaveOk()
Catch saveException As EntityManagerSaveException
ProcessSaveFailure(saveException)
Catch
Throw ' re-throw unexpected exception
End Try
End Sub
The serious failure interpretation and recovery work is in the ProcessSaveFailure method,
which we leave to you. Your application should determine how to process save errors, and
recover from then when possible.
EntityManagerSaveException
The EntityManagerSaveException is raised for all save-related exceptions.
If you've added a handler to the EntityManager's EntityServerError event, that handler will
be called first when a save-related exception occurs. If there is no handler or it doesnt handle
the exception, the EntityManager throws it again, now in the context of the SaveChanges call.
We recommend that you do not handle save exceptions in an EntityServerError handler; leave
that to the code near your SaveChanges call that traps and interprets save failures.
The EntityManagerSaveException inherits from EntityServerException, supplementing it with
information about which entity/entities in the local cache caused the problem.
There are several properties on the EntityManagerSaveException that can be very useful in
diagnosing the problem that occurred.
Property
Property
type
Description
EntitiesWithE
rrors
IList<Obj
ect>
A list of the entities with errors. In practice, this will usually be a list of one --
the first entity to fail --. The idea here is that a non-transactional save might
have multiple errors because one error would not stop the process, or
multiple entities may have failed validation. Since DevForce only offers
transactional saves to the datastore, the first entity to fail within a
transaction causes the transaction to rollback, so no other entities are
saved.
InnerExceptio
n
Exceptio
n
The precipitating exception, whether from an attempt to connect to the
data source or an exception from the data source itself such as a
concurrency conflict or referential integrity violation.
FailureType
FailureTy
pe
A classification of the error that cause the problem. Several
FailureTypes are possible.
FailureType Description
Connection
The Entity Manager could not reach the data source. There might be a network
connection problem or the data source itself could be down.
Data The data source threw an exception such as a referential integrity violation.
Concurrency There was a concurrency conflict.
Validation One or more entities failed server-side validation.
Other Could be anything.

What happens to any local entities after a save fails
These entities remain in the cache and retain exactly the values and setting they had before the
save attempt. This means that you may be able to correct the entities and attempt to re-save
them.
Manage concurrency
Anytime we save an entity in a multi-user distributed environment, there is the possibility that
another user on another machine has saved their own version of the same entity since we last
queried for our own copy of the entity. This page describes the mechanisms for managing
concurrency.


The problem
A multi-user application must decide how to resolve the conflict when two users try to update
the same entity. Consider the following:
1. I fetch the Employee with Id = 42
2. You fetch the Employee with Id = 42
3. You change and save your copy of the Employee with Id = 42
4. I try to save my copy of the Employee with Id = 42
Is this really going to happen?
There is always a risk that another client or component will change the data source entity
while we are holding our cached copy of it. The risk grows the longer we wait between the
time we fetch the entity and the time we save or refresh it. In offline scenarios, the time
between fetch and update can be hours or days. There could be a great many concurrency
conflicts waiting to happen.
If I save my copy now, should it overwrite the one you saved?
If so, weve chosen "last-in-wins" concurrency checking. My copy replaces your copy; your
changes are lost.
This is the default in DevForce but we strongly recommend that you adopt another type of
concurrency control. Permitting one user to blithely overwrite changes that another user made
can be dangerous or even fatal.
There is an enormous body of literature on this subject available on the web by searching for
"concurrency checking".
Basic mechanics of concurrency detection
DevForce defers to the ADO.NET Entity Frameworks mechanism for detecting concurrency
conflicts at the time an update is submitted to the back-end data source.
The Entity Framework (EF) permits the developer to designate, in the Entity Model, one or
more entity properties as concurrency properties by setting its "Concurrency Mode" to
"Fixed". Note that EF does not allow you to define a concurrency property within a Complex
Type.
When a client application submits an update order against such a model to the EF, the EF
prepares a SQL Update statement. To that statement it adds a WHERE clause that ensures that
all columns designated as a concurrency columns have the same value they did when the
record was last retrieved by the submitting application. (In other words, they have not been
changed in the meantime by another user.) If that proves not to be the case, the exception
thrown by the back-end data source will be propagated back down the applications calling
chain.
This approach works only if the concurrency properties are updated with each successful
save. Entity Framework handles concurrency violation detection but not concurrency property
update. It is the developers responsibility to ensure that the update happens.
You can perform the update yourself, tell DevForce to do it, or rely on the database to update
the corresponding concurrency column itself (as it might do with an update trigger).
You tell DevForce which approach to take by setting each concurrency property's
"Concurrency Strategy" in the EDM Designer.

You can pick one of six concurrency property update strategies:
Strategy Name Strategy for updating the concurrency property
AutoGuid DevForce replaces the existing property value with a new GUID.
AutoDateTime DevForce replaces the existing property value with the current Date/Time.
AutoIncrement DevForce increments the existing property value by 1.
Server
Callback
DevForce finds your custom class that implements the IConcurrencyStrategy
interface and calls its SetNewConcurrencyValue() method, identifying the
concurrency property and the entity-to-update in the parameters. Your
implementation of SetNewConcurrencyValue() updates the property.
Client
Your custom code in the client application updates the property before sending
modified entities to the server to be saved.
None
Neither you nor DevForce update the property. Appropriate when the data store
automatically updates the concurrency column as it might do with a trigger.
Note that some of the strategies only apply to properties of specific types: clearly we cannot
force a GUID value into an integer property, or a DateTime value into a boolean property, and
so forth. It remains the developers responsibility to handle any concurrency exception thrown
by the back end.
Here's an example:

A. The RowVersion concurrency property of the Customer conceptual entity
B. The "Concurrency Strategy" DevForce uses to update the concurrency property
C. The "Concurrency Mode" (Fixed) tells Entity Framework that this is a concurrency property
The "Concurency Strategy" in this example is None meaning that we expect the database to
update the RowVersion automatically, probably with an update trigger. Alternatively,
DevForce would update it if we picked AutoIncrement.
Remember:
1. Set the Entity Framework "Concurrency Mode" to Fixed or nothing happens.
2. When "Concurrency Strategy" is Auto, DevForce updates the property for you;
otherwise, you handle update whether on server, client, or data tier.
One concurrency column, or many?
Since the Entity Framework permits you to designate any number of columns as concurrency
columns, it may be tempting simply to designate them all. Thats one way of making sure
that, if anything in the record has been changed by another user since you got your copy, a
concurrency conflict will be diagnosed.
This may be your only alternative if you have no design access to the database, but be aware
that there will be a performance impact. Every update will be accompanied by a flurry of
activity comparing values. As with other performance issues, you should do some upfront
testing to determine whether the performance impact is unacceptable, or even significant.
If you do have design access to the database, or youre fortunate enough to inherit a database
already designed the way you want it, its generally a better alternative to provide a single
column that is guaranteed to be updated whenever anything else is, and to use that as your
sole determinant of a concurrency conflict. A simple integer column that is incremented each
time the record is updated will do quite nicely; you can also use a GUID, timestamp, or any
other type and methodology that guarantees that the value will change in a non-cyclical way.
As you have seen, DevForce makes it easy for you to make a column auto-updating.
Pessimistic versus optimistic concurrency checking
There are two popular approaches to concurrency checking: pessimistic and optimistic.
In pessimistic concurrency, we ask the data source to lock the data source entity while we
examine it. If we change it, we write it back to the data source. When we are done looking at
it or updating it, we free the lock. While we have it locked, no one else can see or use it.
This approach holds up other users trying to reach the object we hold. It gets worse if we need
many objects at once. There are potential deadlocks (I grab A, you grab B, I want B too, but
cant get it, so I wait. You want A also, but cant get it, so you wait. We both wait forever).
There are more complicated, less draconian implementations to this approach but they amount
to the same punishing performance.
Under optimistic concurrency, we dont lock the table row. We bet that no one will change
the source data while were working with it and confirm our bet when (and if) we try to
update the data. The mechanism works as follows.
We fetch a copy of the table row and turn it into a business object. We work with this copy of
the data source entity. We may decide to update the entity or mark it for deletion. When we
save an altered entity, the business object server converts our intention into a data source
management command. That command, in the process of updating or deleting the supporting
table row, confirms that the row still exists and has not changed since we fetched it. If the row
is missing or has changed, the command fails and its up to the application to figure out what
to do about it.
Changes are comparatively rare so we have reason to be optimistic that the row will be
exactly as we last found it.
Only optimistic concurrency checking is performed in both DevForce and the Entity Framework.
Resolving concurrency collisions
Our optimism is usually rewarded. Occasional disappointment is inevitable. Eventually, we
will encounter a conflict between our cached entity, with its pending changes, and the newly-
updated data source entity.
We will want to resolve that conflict one way or the other. The possible resolutions include:
Preserve the pending changes and ask the user what to do.
Abandon the pending changes and re-fetch the entity.
Arrange for the cached entity to become the current entity while preserving the pending
changes
Compare the cached entity with the current data source entity and merge the difference per
some business rules or as guided by the user.
1st choice - Stop and ask
The first choice is the easiest place to start. We do nothing with the entity and report the
problem to the user. The cached entity cannot be saved. We leave it up to the user to decide
either to abandon the changes (option #2) or push them forward (options #2 and #3).
The remaining options involve re-fetching the entity from the data source. They differ in what
they do with the entity retrieved a difference determined by the MergeStrategy and how we
use it.
C# aManager.RefetchEntity(anEntity, aMergeStrategy);
VB aManager.RefetchEntity(anEntity, aMergeStrategy)
2nd choice - Discard local changes and refresh from the datasource
The second choice uses the OverwriteChanges strategy to simply discard the users changes
and update the entity to reflect the one current in the datasource. While unmatched in
simplicity, it is almost the choice least likely to satisfy the end user. If this is the only option,
we should have the courtesy to explain this to the user before erasing her efforts. Note that in
many scenarios concurrency collisions occur so infrequently that this can be a very reasonable
choice.
3rd choice - Force the original thru despite concurrency violation
The third choice makes the cached entity current by re-fetching with the
PreserveChangesUpdateOriginal strategy. This strategy causes the cached entity to trump the
current datasource entity with a little trickery.
The refetch replaces the cached entitys original version, ( see EntityState discussion) with
the values from the current data source entity but it preserves the cached entitys current
version values, thus retaining its pending changes.
The cached entitys original concurrency column value now matches the concurrency column
value in the datasource record.
C#
// the current value of the property in the cached entity
Employee.PropertyMetadata.FirstName.GetValue(anEmployee,
EntityVersion.Current);
// the value from the datasource when most recently retrieved
Employee.PropertyMetadata.FirstName.GetValue(anEmployee,
EntityVersion.Original);
VB
' the current value of the property in the cached entity
Employee.PropertyMetadata.FirstName.GetValue(anEmployee, _
EntityVersion.Current)
' the value from the datasource when most recently retrieved
Employee.PropertyMetadata.FirstName.GetValue(anEmployee, _
EntityVersion.Original)
The effect is as if we had just read the entity from the datasource and applied the users
changes to it.
If we ask the persistence layer to save it now, the datasource will "think" that we modified the
most recently saved copy of the entity and welcome the changed record.
This option is much like "last one wins" concurrency with a crucial difference: it was no
accident. We detected the concurrency collision and forced the issue in accordance with
approved business rules.
PreserveChangesUpdateOriginal strategy works only if the entity is governed by optimistic
concurrency. If the entity lacks a concurrency column, the refetch uses the OverwriteChanges
strategy instead.
Of course we wouldnt be talking about concurrency resolution if there were no concurrency
columns.
4th choice - Merge local changes with refetched data
The fourth possibility begins, like the third, with a re-fetch governed by the
PreserveChangesUpdateOriginal strategy. This time we dont forcibly save the cached entity.
We execute business logic instead which compares the current and original versions, column
by column, deciding whether to keep the locally changed value (the "current" value) or the
datasource value (now tucked inside the "original" value).
Such logic can determine if and when the cached entitys values should prevail. The logic
may be entirely automatic. Alternative, the program could present both versions to the user
and let her decide each difference.
Concurrency and the object graph
One interesting concurrency issue revolves around the scope of concurrency checking. Have I
changed an Order if I add, change or delete one of its OrderDetail items? If I change the
name of a customer, have I changed its orders?
These considerations have to do with concurrency control of the business object graph.
DevForce does not support graph concurrency directly. DevForce supports single-table,
business object proper concurrency control.
The developer can achieve the desired degree of graph concurrency control by employing
single-table checking within a properly conceived, transactional concurrency plan.
It doesnt have to be wildly difficult. In brief, the developer adds custom business model code
such that
Added, changed, or deleted children entities always modify their parents.
An application save attempt always includes the root entity of the dependency graph.
During a save attempt, the root entity ensures that its children are included in the entity-save
list.
These children include their children.
Concurrency and mutually dependent entities
What if a bunch of entities are mutually dependent?
Suppose we have an order and its details. User A adds two more details and changes the
quantity on a third. She deletes the fourth detail and then saves.
In many applications, an order is never less than the sum of its parts. The order and every one
of its details must be treated as a unit at least for transactional save purposes. We will describe
this network of dependency as a "Dependency Graph".
Detection
Continuing our story and standing at an Olympian distance with an all knowing eye, we see
that User B changed the fifth order detail and saved before User A tried to save her
changes.
User A didnt touch the fifth order detail. She wont know about the change because there
will be no concurrency conflict to detect; she cant detect a concurrency conflict unless she
save the fifth order detail and she has no reason to do so.
If this worries you (it worries me), you may want to establish business rules that detect
concurrency violations for any of entity in a dependency graph. A good approach is to
Identify the root entity of the graph (Order) and
Ensure that a change to any node in the graph (OrderDetail) causes the root entity to change.
User Bs change to the fifth detail would have meant a change to the order. User As
changes also modified the order. User As save attempt will provoke a concurrency violation
on the root entity, the order.
Resolution
Now that User A has learned about the violation, what can she do? There is no obvious
problem. Neither A nor B changed the order entity itself so there are not differences to
reconcile. There is only the tell-tale fact that their concurrency column values are different.
It doesnt seem proper to proceed blithely, ignoring the violation and proceeding as if nothing
happened. User A should suspect something is amiss in the details. The application should
re-read all details, even those the user didnt change. It should look for differences at any
point in the graph and only after applying the application-specific resolution rules should it
permit the entire order to be saved again.
What are those resolution rules? We suggest taking the easiest way out if possible: the
application should tell the User A about the problem and then throw away her changes.
There must be something fundamentally wrong if two people are changing an order at the
same time. In any case, the complexity of sorting out the conflict and the risk of making a
total mess during "reconciliation" argue for a re-start.
If you cant take the easy way out if you have to reconcile here are a few pointers.
It is probably easiest to use a temporary second EntityManager for the analysis. A single
EntityManager can only hold one instance of an entity at a time and we need to compare two
instances of the same entity. This is manageable if there is only one entity to deal with
weve seen how to use the current and original versions within each entity to carry the
difference information.
This trick falls apart when we are reconciling a dependency graph. Instead well put User As
cached order and its details in one manager and their dopplegangers from User B in another.
The author thinks it is best to import User As order and details into the second manager and
put User Bs version into the main manager by getting them with the OverwriteChanges
strategy. This seems counter-intuitive but there are a couple of good reasons.
We can ImportEntities into the second manager without logging it in. Wed have to log in the
second manager before we could use it to get GetEntities. This is not hard, but avoiding it is
even easier!
The application probably should favor User Bs order; if so that order will be in the main
manager where it belongs.
Show some restraint
The orders entire object graph is not its dependency graph. The order may consist of details
but that may be as far as it goes.
For example, every detail is associated with a product. If User B changed the fifth details
product name or its color, should this provoke a concurrency conflict? It User C updated the
orders customer name, does that mean all orders sold to that customer must be scrutinized for
concurrency collisions.
Most businesses will say "no".
Manage the save transaction
EntityManager save methods can save a single business object, a list of objects, or all entities
with pending changes.
All EntityManager saves are transactional by default. When the developer saves more than
one entity at a time, DevForce processes them together as a single unit of work. Either every
save succeeds, or they are all rolled back.
Behind the scenes, DevForce causes the necessary INSERT, UPDATE, and DELETE
statements to be wrapped within "Begin Transaction" and "Commit Transaction" or "Rollback
Transaction" statements. If all succeed the transaction is committed. If any fail, the data
source is restored to its pre-transaction condition.
SaveOptions.TransactionSettings

The transactional nature of any save is controlled by the value of the TransactionSettings
property on the SaveOptions class. Recall that every save has a SaveOptions instance
applicable to it. This is either the EntityManager's DefaultSaveOptions or a standalone
SaveOptions instance specified within the SaveChanges call.
The TransactionSettings property is of type TransactionSettings and contains the following
properties, all of which can be set.
Property PropertyType Default value Description
IsolationLevel IsolationLevel ReadCommitted
Determines the transactions locking
behavior. Please consult your database
documentation for more info.
Timeout Timespan
TimeSpan(0, 1, 0)
- 1 minute
The timeout period for the transaction.
UseTransactionScope bool true
It is highly recommended that this be set to
true (default). It is this setting that causes a
transaction that crosses database
boundaries to escalate to use the DTC
(Distributed Transaction Coordinator).
Most SQL databases define different degrees of consistency enforcement called "isolation
levels". Each database vendor has a different default isolation level and a proprietary syntax
to change it. Setting the IsolationLevel above is dependent upon the support of both the
database vendor and the .NET ADO.NET provider being used. In some cases, settings may
need be made within the database itself or with proprietary information embedded in the
connection string. Consult the database vendors documentation.
Distributed transactions
By default, DevForce also provides transactional integrity when saving entities to two or more
data sources. These data sources can be of different types from different vendors. Their data
source managers must support the X/Open XA specification for distributed transactions.
By setting the UseTransactionScope property mentioned above to "true" ( the default), the
developer is instructing DevForce to use the .NET Enterprise Services (AKA, COM+)
Distributed Transaction Coordinator (DTC) to handle transaction management when more
than one database is involved. Be sure to enable DTC in your system. (Control Panel >
Administrative Tools > Services)
DTC performs a two phase commit. In the first "prepare" phase all parties to the transaction
signal their readiness to commit their parts of the transaction. In so agreeing they must
guarantee that they can complete their tasks even after a crash.
If any participant does not agree, all parties roll back the transactions they have underway.
If all participants agree, the transaction moves into the second, commit phase in which the
parties actually commit their changes.
If the transaction is successful, the entities are re-queried.
Save lifecycle
Last modified on March 21, 2011 19:13
Workflow for a save
During the execution of a save a number of discrete steps are followed. DevForce provides
several points along the way where a developer can intervene and modify the execution path.
This page describes this sequence of steps and the interception points.
Component Action
Client Tier
Application
Code
The client application adds, modifies and deletes any number of business
objects on the client.
The client application asks a EntityManager to save all pending changes.
Client Tier
EntityManager
Makes a save list of all of the new, modified, and deleted entities in the
EntityManager entity cache.
Fires the Saving event, passing in the list of entities to be saved. The listener
can add or remove entities from this list or cancel the save. For now, let's
assume that application listener just okays the save.
If this is a partial save, meaning that only specified entities are being saved
instead of all added, modified, or deleted entities, then a check is performed
to insure that if any entity in the graph of entities being saved contains a
temporary id, that all other entities that have a reference to this same
temporary id are also included in the save. If this is not the case an Exception
is thrown with an explanation of which entities are in violation of this rule.
Transmits the list of entities to be saved to the EntityServer.
Middle Tier
Server authenticates the user. Let's assume success.
EntityServer The EntityServer creates a new EntityServerSaveInterceptor or an instance of
a developer customized subclass.
In the EntityServerSaveInterceptor the AuthorizeSave method can be used to
perform security checks; the ValidateSave method can be used to perform
server-side validation.
When the EntityServerInterceptor.ExecuteSave method is called, where
DevForce performs a temporary id to permanant id conversion and then
forwards the saves to the Entity Framework for execution.
Data Tier
Data Source
Performs the persistence operations. If there are no failures, it commits them; if
there is a single failure, it rolls them all back.
Middle Tier
EntityServer
If the transaction failed, returns to the EntityManager the identity of the
culprit entity and the exception raised by the data source. The EntityManager
stores this information in the SaveResult and returns to the client application.
Workflow ends. Otherwise
The transaction succeeded. The EntityServer re-queries the database(s) for all
of the inserted and modified entities that are sourced in databases, thus
capturing the effects of triggers that fired during save.
Converts the (potentially) revised data into entities and sends them to the
client side EntityManager.
The servers local copy of the entities go out of scope and the garbage
collector reclaims them. This enables the object server to stay stateless.
Client Tier
EntityManager
Performs id fixup, converting temporary ids to permanent ids based on a
mapping between the two generated by the EntityServer during the save and
passed back to the client in the previous step.
Replaces cached entities with updates from EntityServer. They are marked
unchanged because they are now current.
Raises the Saved event with list of saved inserted and modified entities.
Client Tier
Application
Code
The application resumes.
Client-side save lifecycle events
The client side lifecycle of a save consists of two events on the EntityManager; Saving and
Saved. These are summarized in the table below.


Saving and Saved events
Event EventArgs Comments
Typical Uses of the Corresponding
Event Handler
Saving EntitySavingEventArgs
Raised when the
EntityManager is preparing
to save changes.
Provides access to the
collection of entities
submitted for the save.
Permits cancellation of the
save.
Modify the object submitted for
saving, or refuse the request to
perform inserts and/or updates.
Saved EntitySavedEventArgs
Raised when the
EntityManager has
completed a saved
(including a cancelled
save).
Provides access to the
collection of entities saved.
Modify the saved object (which might
be different from the object submitted
for saving by virtue of triggers that
were fired on the back end to modify
the latter after it was saved).
The EntityManager raises a Saving event shortly after the application initiates a save. It raises
a Saved event upon completion of the save, regardless of whether any entities were saved
successfully. We can add our own event handlers to these events.
The Saving event provides the handler with a list of entities that the caller proposes to save. It
will calculate that list if the method parameters do not prescribe the list. SaveChanges() with
no arguments, for example, is a blanket request to save every added, changed or deleted entity
in cache. The event handler can scrutinize the list, invoke validation methods on selected
entities, clean up others (e.g., clear meaningless error conditions), add additional entities to
the list, and even exclude entities from the list. Lastly, it can cancel the save.
The EntityManager raises the saved event upon completion of the save. The handler receives
a list of the entities that were saved successfully.
In DevForce, saves are always transactional, even across disparate back-end data sources. In
transactional saves, either every entity in the save list is saved or none of them are.
Virtual EntityManager methods

Corresponding to each of these events is a protected virtual method on the EntityManager that
can be used to perform the same task directly in a subclassed EntityManager.
Member Summary
OnSaving The virtual method that a derived EntityManager can override to raise the Saving event.
OnSaved The virtual method that a derived EntityManager can override to raise the Saved event.
EntitySavingEventArgs
Property PropertyType Access Description
Entities IList<Object> get - but the list returned can be modified The list of entities to be saved.
Cancel bool get, set Allows the save to be cancelled.
EntitySavedEventArgs
Property PropertyType Access Description
Entities IList<Object> get Returns the entities saved.
SaveResult SaveResult get Returns the SaveResult - see SaveResult
Exception EntityManagerSaveException get
Returns the exception thrown if an error occurred
during save processing.
Server-side save lifecycle events
The changes-set of entities to be saved are processed by the EntityServer which passes the
change-set through an instance of the DevForce EntityServerSaveInterceptor. You can alter
the course of that processing by creating a 'custom' subclass of the
EntityServerSaveI nterceptor and overriding its virtual properties and template
methods. DevForce can discover the existence of your class automatically.


Interceptor design guidelines
You don't have to write a custom interceptor class. The EntityServer will use the DevForce
EntityServerSaveInterceptor if it doesn't find a custom subclass. Many production
applications do include a custom interceptor.

The EntityServerSaveInterceptor class resides in the IdeaBlade.EntityModel.Server assembly
which must be referenced by the project that contains your custom subclass.
You can write only one custom interceptor. It should be a public class and must have a public
default, parameterless constructor (if it has a constructor).
Please keep your named custom interceptor stateless if possible. DevForce creates a new
instance of this class for each query performed by the server so you generally don't have to
worry about threading issues with instance state. If you decide to maintain static state, give
great care to ensuring safe concurrent access to that state.
Avoid putting anything in the interceptor other than what is strictly necessary to achieve its
purpose. The interceptor is a poor choice for a grab-bag of server-side features.
You don't have to override any of the template methods; the default base implementations all
work fine. You may wish to be explicit in your custom class and override every template
method; your override can simply delegate to the base implementation.
Make sure that the assembly containing your custom interceptor is deployed to the server such
that it can be discovered. Assembly discovery is discussed here.
Interceptor template methods
The EntityServerSaveInterceptor class contains a number of template methods that you can
override to modify the base behavior of the class. These methods are executed at key points
within the server-side part of the save process; you override them in your subclass to perform
custom interventions. They enable you to perform operation both before and after the physical
save to the database (or equivalent backing store).
Most of the template methods have no parameters because all of the relevant data are
provided by properties and methods on each instance of the class. This also allows IdeaBlade
to extend the base class in the future without breaking custom developer code.
Many of the template methods described below return a boolean result with a base
implementation that returns "true". A return value of "true" allows the save to continue. A
return value of "false" causes the save to exit with an exception. There is also a flag available
that may be used to indicate a "canceled" operation.
Note that while the base implementation of the authorization method does not return false, it
will throw an exception it it detects an unauthorized save. It treats an unauthorized save as an
exception, not a cancellation.
protected virtual bool AuthorizeSave()
Override to control whether the user is authorized to perform the save. The base
implementation walks all of the types involved in the save and calls the ClientCanSave
method defined below for each to determine if any unauthorized types are being accessed.
An EntityServerException will be thrown with a PersistenceFailure value of "Authorization" if
any unauthorized types are encountered. You can bypass authorization by simply returning
"true" without calling the base implementation.
protected virtual bool ValidateSave()
Override to extend ( or remove) server-side validation of the data to be saved. The base
implementation of this method will perform "instance validation" for each entity being
saved. If any verification fails, an EntityServerException will be thrown with a
PersistenceFailure type of "Validation". The VerifierEngine property is available in order to
discover what validations will be performed. You can bypass validation by simply returning
"true" without calling the base implementation.
protected virtual bool ExecuteSave()
Override to intercept the save immediately before and after the save request is executed.
The entities involved in the save may be modified before calling the base implementation of
this method and logging or other post processing operations may be performed after the
base implementation is called. Note that the base implementation must be called in order
for the save to be executed. The EntityManager property defined below contains all of the
entities to be saved and its contents may be modified at any time prior to the base
implemention of the ExecuteSave method being called.
protected virtual bool ClientCanSave(Type type)
Override to control which types are authorized to be saved. This method is called from the
base implementation of the AuthorizeSave. It may be overridden to add additional
restrictions or to relax existing ones. If adding restrictions, make sure that the base
implementation is called.
protected virtual void OnError(Exception e, PersistenceFailure failureType)
May be overridden to log errors. No logging is performed by the default implementation.
Virtual Properties
protected virtual bool DefaultAuthorization { get; }
Override this property to change the Default authorization of whether or not authorization
succeeds if no Authorization attributes are found. This property defines the default
authorization behavior for any types that do not have a ClientCanSave attribute defined. The
base implementation returns "true" which means that by default any type not otherwise
restricted is saveable. By returning a "false" here, any types that are not specifically marked
as saveable will restricted.
Other properties
In addition to the above, the following protected read only properties are also available.
Property
Property
type
Used for
Principal IPrincipal The IPrincipal from the user session requesting this operation.
EntityManager EntityManager
Returns an EntityManager holding the entities to be saved. Note
that this is not the original EntityManager on which the
EntityManager.SaveChanges() call was made. This property can be
very useful when overriding the ExecuteSave method. Additional
entities that need to be saved can be added to this EntityManager
or entities that should not be saved can be removed before calling
base.ExecuteSave().
VerifierEngine VerifierEngine
Returns the VerifierEngine which will be used for server-side
validation.
SaveOptions SaveOptions Returns the SaveOptions provided in the SaveChanges call.
IsServerSave boolean
Returns true if the save was issued on the server. This can occur as
a result of an InvokeServerMethod call. This is useful because you
typically do not need to reauthorize a save where the request for
the save originates on the server.
Note that the EntityManager returned by the EntityManager property is NOT the original
client-side EntityManager on which the save request was made. It is a 'preauthenticated'
server-side EntityManager, and its cache is consists of the entities being saved. Because of
its "preauthenticated" nature, there is no Principal attached to this EntityManager and any
operations that it performs bypass regular authentication. Because this EntityManager can
only be accessed on the server from within code deployed to the server all operations that it
performs are considered "priviledged".
Because this EntityManager is untyped, additional entities of any entity type may queried
with it. Queries against this EntityManager are usually composed via a technique shown in
the following example, ( the code below is assumed to be executing within the context of
some EntityManagerSaveInterceptor method). Note the use of the EntityQuery<T>
constructor.
C#
var newQuery = new EntityQuery<Customer>().Where(c => c.CompanyName.StartsWith("S"))
var custs = newQuery.With(EntityManager).ToList();

Handle cascaded deletes
The ability to declaratively state that the delete of one entity should automatically cause the
deletion of some its related "dependent" entities is a relatively common and very useful tool in
the development of a complex domain model. In DevForce and in the Entity Framework these
are called cascaded deletes and the Entity Framework Designer offers support for
declaratively marking up an entity relationship as having a delete "cascade" rule that applies
to it.


Telling EF about a cascaded delete
Within the Entity Framework Designer, every relationship has its own property page that
looks something like the following.

Cascaded deletes are configured by setting either of the "End1 OnDelete" or "End2 OnDelete"
combo boxes to "Cascade".
What this markup actually does in both DevForce and the Entity Framework (EF) is tell EF to
expect that the "database" will perform its own form of cascaded delete for this relationship.
i.e. that the database has some mechanism for insuring that when the records mapped to the
parent entity are deleted that any "dependent" records will be automatically deleted as well.
Let's call this a database "delete rule" for future reference.
Who does what?
To be clear, DevForce (and EF) does NOT take responsibility for cascading the delete in the
database. DevForce does insure that the deletion of any principal entity within an
entitymanager automatically forces the automatic deletion of its related entities also within
the entity manager. Recall that deletion in this context is actually marking the entity for
deletion so that it will actually be deleted from the database during the next SaveChanges call.
In other words, DevForce will attempt to synchronize the EntityManager with the "expected"
state of the database after a delete by understanding that the delete will cause side effect on
the database. But...
DevForce does not retrieve all the dependent entities when an entity is deleted and then issue
deletes for them as well: It only deletes ( marks as deleted) any dependent entities that are already
in memory.
Restated, DevForce expects that deleting the principal entity in the database, will delete all
its dependents in the database. So it makes, what should be, a redundant delete request for
any dependent entities that it knows about, i.e. that are already loaded into the
EntityManager's entity cache.
The rule
This leads a basic rules about cascaded deletes.

If you add an Cascade delete rule to the model, you MUST have a corresponding delete
rulein the database.
It is possible to break this rule if you are willing to insure that anytime that you delete a
principal entity that all of its dependent entities have already been loaded into the
EntityManager as well. We do NOT recommend this.
A problem
There is one interesting, rare, and annoying failure that can occur with this process.
Assume that you have relationships that looks something like:
Category > Product > Order
with cascading deletes set up so that deleting a Category deletes its Products which in turn
deletes its Orders.
Then DevForce will, in some rare cases, be unable to synchronize an EntityManager with the
database when you delete a Category.
This can occur if you have an Order loaded that is related to a Category via an unloaded
Product, and you delete the Category. Under these conditions, DevForce wont know to delete
the Order.
This means the Order will remain in the EntityManager in the unchanged state, despite it
having been deleted in the database.
Save a graph of entities
When performing a save where you specify exactly which entities should be saved, it is
often useful to be able to 'walk' a selected 'graph' of entities related to those that you know
you are saving in order to determine if any other 'related' entities that need to be saved as well.
This could be accomplished by
1) Iterating over each of the 'root' entities that you wish to save
2) For each of these entities iterating over each of the navigation properties that constitute
your selected graph
3) For each of these navigation properties, perform the navigation, using a CacheOnly
FetchStrategy to insure that no 'additional' entities are added to the local cache as a result of
this operation.
4) For only those entities returned from the navigation that have an EntityState that is either
Added, Modified or Deleted.
5) Accumulated these for our eventual result.
6) Repeat step 2 above for each these entities.
But there is an easier way! The EntityManager.FindEntityGraph method does precisely this.


Using the FindEntityGraph method
The EntityManager.FindEntityGraph method is specifically intended to be used to search the
local cache for any entities that are navigable from a list of root entities according to a
specified graph.
C#
public IList<Object> FindEntityGraph(
IEnumerable roots,
IEnumerable<EntitySpan> spans,
EntityState entityState);
VB
public IList(Of Object) FindEntityGraph(
IEnumerable roots, _
IEnumerable(Of EntitySpan) spans, _
EntityState entityState)
Given any entity or entities in a graph, this method collects and retrieves all of the related
entities in the graph. This is a cache-only operation.
Parameter Description
roots A list of entities used as the starting point for retrieving all other related entities.
spans
One or more EntitySpans; this defines the graph to be traversed. An error will be thown
for any span that does not have a matching type in one of the roots.
entityState The EntityState of entities to return. This allows you to filter by EntityState.
An example of its use is shown below:
C#
// Get the root(s).
var roots = listOfEmployeesToSave;

// Get the span(s).
var spans = new List<EntitySpan> {
new EntitySpan(typeof(Employee), EntityRelations.FK_OrderSummary_Employee,
EntityRelations.FK_Order_Details_Orders, EntityRelations.FK_Order_Details_Products)
};

// Find the related entities.
var entityState = EntityState.Added | EntityState.Modified | EntityState.Deleted;
var entities = myEntityManager_em1.FindEntityGraph(roots, spans, entityState);
myEntityManager.SaveChanges(entities);
VB
' Get the root(s).
Dim roots = listOfEmployeesToSave

' Get the span(s).
Dim spans = New List(Of EntitySpan) From {New EntitySpan(GetType(Employee), _
EntityRelations.FK_OrderSummary_Employee, EntityRelations.FK_Order_Details_Orders, _
EntityRelations.FK_Order_Details_Products)}

' Find the related entities.
Dim entityState = entityState.Added Or entityState.Modified Or entityState.Deleted
Dim entities = myEntityManager_em1.FindEntityGraph(roots, spans, entityState)
myEntityManager.SaveChanges(entities)
But the roots do not all have to be of the same type. For example:
C#
// Add root(s).
var roots = new List<Entity> { emp, supplier };

// Add span(s).
var spans = new List<EntitySpan> {
new EntitySpan(typeof(Employee), EntityRelations.FK_OrderSummary_Employee,
EntityRelations.FK_Order_Details_Orders),
new EntitySpan(typeof(Supplier), EntityRelations.FK_Products_Suppliers,
EntityRelations.FK_Products_Categories)
};

// Find the related entities.
var entityState = EntityState.Added | EntityState.Modified | EntityState.Deleted;
var entities = myEntityManager_em1.FindEntityGraph(roots, spans, entityState);
myEntityManager.SaveChanges(entities);
VB
' Add root(s).
Dim roots = New List(Of Entity) From {emp, Supplier}

' Add span(s).
Dim spans = New List(Of EntitySpan) From {New EntitySpan(GetType(Employee), _
EntityRelations.FK_OrderSummary_Employee, EntityRelations.FK_Order_Details_Orders), _
New EntitySpan(GetType(Supplier), EntityRelations.FK_Products_Suppliers, _
EntityRelations.FK_Products_Categories)}

' Find the related entities.
Dim entityState = entityState.Added Or entityState.Modified Or entityState.Deleted
Dim entities = myEntityManager_em1.FindEntityGraph(roots, spans, entityState)
myEntityManager.SaveChanges(entities)


Secure
Last modified on March 16, 2011 11:58
Every application, whether a 2-tier or n-tier desktop application used only within an
organization or an ASP.NET or Silverlight application accessible across the internet, must
consider its threat exposure.
Consider the following:
Any client-side code, including Silverlight applications, can be easily disassembled (e.g., using
Reflector or Silverlight Spy)
All messages to and from a server can be easily intercepted and monitored (e.g., using
Fiddler)
If we assume that both the client and the transport are exposed and can be compromised, then
we need to consider the risks to the application, its users, and the organization. Does your
application contain sensitive information which should be restricted to certain users? Does it
contain personal information such as an individual's health record or financial data? Are only
paid users allowed access? If guest users are permitted, what data and operations can they
access?
Silverlight applications have additional challenges. Because its often used to create public-
facing applications, Silverlight is inherently more dangerous than in-house applications that
run behind a firewall or over a VPN. Will your Silverlight application run out-of-the-
browser? Will it use Isolated Storage? Will it access services on other domains?
As a developer you must ask all these questions, and many more, as you build and secure
your application. In the following sections we'll look at how DevForce can help in
authenticating and authorizing users, and other actions you can take to build a secure
application.
In the following topics we'll discuss various aspects of securing your application:
Authentication - the process of validating a user's identity
Authorization - how to ensure the user accesses only the information allowed
Additional steps - additional steps you can take in locking down your application
Additional Resources
Since we can't cover every aspect of security here, we encourage you to learn more about this
topic. Here are a few links to get started:
Silverlight Security MSDN article
Ward Bell's DevConnections 2010 slides on Silverlight security
See just how easy it is to eavesdrop on HTTPS traffic with Fiddler
Authenticate
Last modified on March 16, 2011 13:19
Authentication is the act of confirming that users are who they claim to be. Authenticating a
claim might be done using ASP.NET security, Active Directory, Windows Identity
Foundation, or a custom implementation.
DevForce has built-in hooks to support the authentication scheme of your choice, and
includes out-of-the-box support for ASP.NET security.
Unless your application allows "guest" access, when your application starts you should obtain
user credentials. These might be in the form of a userid and password (when using ASP.NET
security this is called Forms authentication), or it might mean obtaining an "ambient"
credential, such as the current Windows userid or HttpContext.Current.User.
In DevForce, an EntityManager must be "logged in" to the EntityServer in order to access
data or services. As a developer you have control over how and when this login occurs. You
determine the credentials your application accepts, you call a Login method to authenticate
the user, and you write the server code to perform the authentication via the
IEntityLoginManager.
When you determine a user is authenticated, you provide that information to DevForce in the
form of an IPrincipal. If you're not familiar with the IPrincipal interface, it, along with the
IIdentity interface, is a flexible means of holding information on who a user is and their
roles. It does not hold user credentials or claims, but does indicate how the user was
authenticated. The DevForce implementation of these interfaces is the UserBase.
On the server DevForce will tuck this IPrincipal away, and return a token called a
SessionBundle to the client. The SessionBundle contains an encrypted credential, encrypted
using the EntityServer's specific "session encryption key". The SessionBundle is transmitted
with every request to the server, where DevForce first validates the bundle before proceeding
with the request. In Azure and other load balanced environments, the encrypted credential in
the bundle allows the user to be authenticated by any server having the same session
encryption key. (This key is configurable and we'll see more on this key later.) Once logged
in, the server keeps track of each user's last access, and will time the session out after a
configurable period of inactivity.
Guest Users
A guest user is an anonymous user -- one who has not provided a credential and is therefore
not authenticated. We noted above that an EntityManager must be logged in to an
EntityServer, and that every request to the server is accompanied by a token which is
validated before proceeding. How does this work with anonymous users? If you do not call
the EntityManager Login method and supply a credential, DevForce will do it for you when
necessary. DevForce first determines whether you have disabled anonymous access via a
configuration setting; if not, a UserBase is constructed for the guest user indicating the user is
not authenticated and has no assigned roles.
The DevForce default is to allow anonymous users, but it is a very good idea to disable this
feature unless your application intentionally allows it. When anonymous logins are disabled,
an exception is thrown for the Login attempt, and no further access to the EntityServer is
permitted from the EntityManager.
To disable guest access, set the AllowAnonymousLogin flag to false in the web.config or
server .config file:
XML <objectServer>
<serverSettings allowAnonymousLogin="false" />
</objectServer>

The Login process
The process of logging in a user involves a handshake between the Entity Manager and the
Entity Server. The EntityManager Login method is used to supply a client credential to the
server in the form of an ILoginCredential. The server in turn tries to authenticate the user via
an implementation of the IEntityLoginManager, and returns user information back to the
EntityManager in the form of an IPrincipal. All these interfaces may seem confusing, but
they mean that you the developer are in control of the login process.


On the client
Authentication begins on the client, when Login is called. Until a Login successfully
completes, the EntityManager may not communicate with the EntityServer for data or
services.
Login
At its simplest, gather user credentials and call the EntityManager Login method (only the
asynchronous version is available to Silverlight applications):
C#
bool Login(ILoginCredential credential);

LoginOperation LoginAsync(ILoginCredential credential);
VB
Boolean Login(ILoginCredential credential)

LoginOperation LoginAsync(ILoginCredential credential)
It's worth noting that the credential is passed in clear text. Use a secure channel (such as SSL) or
provide your own encryption of the credential data if secure communications are required.
What if you don't have a credential? For example, you're using Windows credentials, or
allow guest access, or you're using ASP.NET security with Windows authentication or a
persistent or ambient authentication ticket. In these cases, calling the Login method with a
null credential indicates that the EntityServer will determine how to handle the login
request. When using ASP.NET security, the built-in implementation will try to use the
current user information from the HttpContext.
After the EntityManager is logged in, you can access the returned IPrincipal through the
EntityManager.Principal property.
If the Login failed, a LoginException is returned. When called synchronously the exception is
thrown; when called asynchronously the exception is available in the LoginOperation.Error
property.
Logout
The EntityManager Logout method performs another handshake with the EntityServer, telling
it to remove session information for the user. Logout also clears the IPrincipal for the
EntityManager, and further requests to the server from the EntityManager are disallowed until
it again logs in.
Many applications do not explicitly call Logout, and it's not strictly necessary. The user
session information on the server will expire after a period of inactivity. If your application is
available on public computers it's generally a good idea to logout either by user request or
when the application closes.
(Note that the user session information stored on the server has a very small footprint. It's
simply the SessionBundle containing encrypted credentials and a few additional fields
tracking last activity; no other data is stored.)
On the server
DevForce supplies built-in login processing on the server if using ASP.NET security. When
not using ASP.NET security you must provide a custom implementation of the
IEntityLoginManager interface, otherwise all users will be logged in as "guest" users.
Implementing IEntityLoginManager
The IEntityLoginManager is responsible for verifying a user's identity. Add a class which
implements the interfaces methods, and ensure that DevForce can find the class by placing
the assembly in the same folder as the executable or bin folder. The assembly needs to be
deployed only on the server, since login authentication processing is not performed on the
client.
The interface prescribes two methods: Login and Logout.
Login
Your Login method will be passed the ILoginCredential that the client used in the
EntityManager.Login call. Note if you call EntityManager.Login without credentials, or allow
an implicit login to take place, that the credential will be null. Your code should handle this.
An EntityManager is also passed to the method to allow you to easily query your domain
model. The EntityManager here is a special, server-side EntityManager instance which is
already connected to the EntityServer and does not require a login; it is not the same
EntityManager from which you called Login on the client. This EntityManager is not an
instance of your sub-typed domain-specific EntityManager either, but rather of the base
EntityManager class.
From your Login method, you should return a type implementing IPrincipal. Common
implementations are GenericPrincipal, WindowsPrincipal, or UserBase; but any serializable
type is allowed. Neither GenericPrincipal nor WindowsPrincipal is available in Silverlight
applications, but you can use the DevForce UserBase class or implement a custom
IPrincipal. If the credentials supplied are not valid, you should throw a LoginException
indicating the cause of the failure.
Logout
The Logout method allows you to perform any processing needed when the user logs off. You
might find this useful to perform session-level auditing or resource cleanup. Even if you have
no need for logout processing, you must still implement an empty method.
Sample
Heres a sample class implementing the IEntityLoginManager interface. It returns a
UserBase from the Login method, and requires no special Logout processing.
Note that this sample performs no actual authentication of the user credentials, and should
therefore not be used in a real application! It also throws an exception if a credential was not
supplied. The sample is intended only to show the simple mechanics of the interface.
C#
public class LoginManager : IEntityLoginManager {
public IPrincipal Login(ILoginCredential credential,
EntityManager entityManager) {
if (credential == null) {
throw new LoginException(LoginExceptionType.NoCredentials,
"No credentials supplied");
}
// Return an IPrincipal. Any serializable type may be returned,
// here we use the DevForce UserIdentity and UserBase classes.
var identity = new UserIdentity(credential.UserName, "Custom", true);
var principal = new UserBase(identity);
return principal;
}

public void Logout(IPrincipal principal,
EntityManager entityManager) {
// No special processing needed.
}
}
VB
Public Class LoginManager
Implements IEntityLoginManager
Public Function Login(ByVal credential As ILoginCredential, _
ByVal entityManager_Renamed As EntityManager) As IPrincipal
If credential Is Nothing Then
Throw New LoginException(LoginExceptionType.NoCredentials, _
"No credentials supplied")
End If
' Return an IPrincipal. Any serializable type may be returned,
' here we use the DevForce UserIdentity and UserBase classes.
Dim identity = New UserIdentity(credential.UserName, "Custom", True)
Dim principal = New UserBase(identity)
Return principal
End Function

Public Sub Logout(ByVal principal As IPrincipal, _
ByVal entityManager_Renamed As EntityManager)
' No special processing needed.
End Sub
End Class
Ensuring that Login will fail if an IEntityLoginManager class is not deployed
To ensure that your custom IEntityLoginManager is found and used, you can set a
configuration option which will cause DevForce to throw an exception when not found. By
default the EntityServer will resort to it's own authentication processing when a custom
implementation is not found and ASP.NET security is not in use: that processing ignores
supplied credentials and logs all users in as guests. This is rarely what your applications
wants, except in those rare cases where only anonymous access is provided in the
application.
If you've supplied an IEntityLoginManager and you want to ensure that it is in fact being
used, set the LoginManagerRequired flag in the web.config or server .config to true:
XML <objectServer>
<serverSettings loginManagerRequired="true" />
</objectServer>
Customizing the Login process
DevForce will usually find your custom implementations without any extra work on your
part. See the topic on extending DevForce for more information on how to ensure your
custom types are discovered.
ILoginCredential Any serializable type implementing the ILoginCredential interface can be
used. The LoginCredential, and the FormsAuthenticationLoginCredential are the DevForce-
supplied implementations. The credential supplied in the EntityManager.Login call is the
credential received in the IEntityLoginManager.Login. The class defining the
ILoginCredential must be available on both client and server.
IPrincipal Any serializable type implementing System.Security.Principal.IPrincipal can be
returned from the IEntityLoginManager.Login method. The object is returned to the client and
is available via the EntityManager.Principal property on the EntityManager instance on
which Login was called. The IPrincipal is also available to other server methods. The class
defining the IPrincipal must be available on both client and server. The IIdentity held by the
IPrincipal must also be a serializable type and available on both client and server.
If you sub-type either UserBase or UserIdentity, the DevForce default implementations of
IPrincipal and IIdentity, your classes must be:
1. Marked with the DataContract attribute. Also be sure to mark any custom properties which
should be transmitted between tiers with the DataMember attribute.
2. Included on both the client and server! You won't be able to login if your custom classes
aren't defined in assemblies deployed to both client and server tiers.
LoginException. Any serializable type extending LoginException can be thrown for login
failures. To ensure that your custom exception is received correctly on the client, you must
also implement a constructor accepting the message, and a constructor accepting a dictionary
of any custom properties. DevForce will automatically serialize any custom properties via a
Dictionary<string, object>, and will call the appropriate constructor when building the
exception on the client. The class defining the custom exception must be available on both
client and server. For example:
C#
[DataContract]
public class CustomLoginException : LoginException {
public CustomLoginException(string message, int severity) :
base(message) {
Severity = severity;
}

public CustomLoginException(string message,
Dictionary<string, object> userData) : base(message) {
Severity = (int)userData["Severity"];
}
[DataMember]
public int Severity {
get;
internal set;
}
}
VB
<DataContract()> _
Public Class CustomLoginException
Inherits LoginException
Public Sub New(ByVal message As String, ByVal severity As Integer)
MyBase.New(message)
Me.Severity = severity
End Sub

Public Sub New(ByVal message As String, _
ByVal userData As Dictionary(Of String, Object))
MyBase.New(message)
Severity = CInt(Fix(userData("Severity")))
End Sub

Private privateSeverity As Integer
<DataMember()> _
Public Property Severity() As Integer
Get
Return privateSeverity
End Get
Friend Set(ByVal value As Integer)
privateSeverity = value
End Set
End Property
End Class
How to authenticate without logging in
Now that we've covered all the intricacies of the login process, it's time to cover how the
EntityManager can be authenticated without ever calling Login.
There are several ways, and they're all based on sharing an existing credential - well, it's not
truly the credential the user supplied, since that is discarded after a login, it's the
SessionBundle, the token representing the user.
Create an EntityManager via the copy constructor
C# var newEntityManager = new EntityManager(anotherEntityManager);
VB Dim newEntityManager = New EntityManager(anotherEntityManager)
The new EntityManager will have the same connection state, and share the user information
from the other EntityManager.
Use EntityManager.LinkForAuthentication
C#
var entityManager = new EntityManager();
entityManager.LinkForAuthentication(anotherEntityManager);
VB
Dim entityManager = New EntityManager()
entityManager.LinkForAuthentication(anotherEntityManager)
)
Use I AuthenticationManager.LinkAuthentication
C# bool LinkAuthentication(EntityManager targetEM);
VB Boolean LinkAuthentication(EntityManager targetEM)
)
The EntityManager will automatically search for an implementation of
IdeaBlade.EntityModel.IAuthenticationManager and call its LinkAuthentication method if it's
not already logged in and any access to the EntityServer is needed.
A sample IdeaBlade.EntityModel.IAuthenticationManager implementation is provided in the
Business Application templates.

Use ASP.NET security
DevForce provides out-of-the-box integration with ASP.NET security features (Membership,
Roles, Profile). These features can be used in any application -- Silverlight, desktop, or
ASP.NET. If developing for Silverlight or ASP.NET, choosing ASP.NET security is often
the right choice over a custom security implementation. ASP.NET security is easy to use,
highly configurable, and well-documented. See http://www.asp.net/learn/security/ for
information on ASP.NET security features.
For Silverlight applications, DevForce provides Visual Studio project templates for a "DevForce
Silverlight Business Application" which automatically use ASP.NET security features without any
additional work or configuration required on your part. See the Business Application Templates for
more information.
In order to use ASP.NET security in DevForce you must set the UseAspNetSecurityServices
flag in the web.config or server .config to enable it. When enabled, DevForce will use the
AspAuthenticatingLoginManager to handle login requests from clients.
XML <objectServer>
<serverSettings useAspNetSecurityServices="true" />
</objectServer>
You must also enable AspNetCompatibility in order to allow the DevForce services to
integrate with ASP.NET services. You set this in the system.serviceModel configuration
section. Here's the relevant element in the system.serviceModel section:
XML <system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
You must enable the ASP.NET services you wish to use in the system.web configuration
section of the config file, as well as choose the type of authentication wanted. These steps are
described below.
Authentication
Authentication in ASP.NET can take either of two flavors Forms or Windows. For either
type of authentication, after a successful Login completes a UserBase instance representing
the user is available on both client and server.
Forms Authentication
Forms authentication involves validating user credentials against a Membership
provider. The default provider uses a SQL Server Membership database, aspnetdb, to store
user information. ASP.NET also supplies a Membership provider for Active Directory, or
you can write a custom provider.
To use Forms authentication, specify this authentication mode in the system.web
configuration section:
XML <system.web>
<authentication mode="Forms" />
</system.web>
In your application you can ask the user for login credentials and pass the credential in the
EntityManager.Login call. DevForce will validate the credentials with the ASP.NET
membership provider. If the user is authenticated, a FormsAuthenticationTicket is issued. If
you want the ticket to be persistent you should pass a FormsAuthenticationLoginCredential in
the Login call, since this credential allows you to set the persistence flag.
You can also call EntityManager.Login with a null argument if your application accepts either
persistent authentication tickets or the user has already logged in as part of the larger
application.
Windows Authentication
When using Windows authentication in ASP.NET the current Windows credentials of the
client are transmitted to the server. This can be used in intranet environments only.
To use Windows authentication, specify this authentication mode in the system.web
configuration section:
XML <system.web>
<authentication mode="Windows" />
</system.web>
Note that additional configuration changes are required both in IIS and in the communications
configuration in order to pass Windows credentials to the EntityServer. These changes are
discussed in the configuration topic.
On your client, call the EntityManager.Login method with a null credential. The
AspNetAuthenticatingLoginManager will check the HttpContext.Current.User for a
WindowsPrincipal representing the user, and from that create a UserBase to be returned to the
client.
Roles
You must enable the Role service in the configuration file in order to use this feature:
XML <system.web>
<roleManager enabled="true" />
</system.web>
With roles enabled, user role information will be obtained from the ASP.NET RoleProvider,
and role-based authorization can be used in your application. Use UserBase.Roles to retrieve
all roles for the user, and UserBase.IsInRole() to determine role membership.
Check the ASP.NET documentation for information on how to create and manage roles and
assign users to roles.
Profile
You must enable the Profile service in the configuration file in order to use this feature, and
define the profile properties wanted. Here's a sample:
XML <system.web>
<profile enabled="true">
<properties>
<!-- Sample properties -->
<add name="WindowSeat" type="bool" defaultValue="false" />
<add name="Building" type="string" defaultValue="A" />
</properties>
</profile>
</system.web>
You also need to extend the UserBase class with the custom properties from your profile.
DevForce will automatically populate these properties from the Profile if the property name
and type match, and the setter is public. Your custom UserBase class must be serializable,
since it will be transmitted between client and server tiers. The DevForce Business
Application project template for Visual Studio uses the Profile service and shows a sample
User class which extends the UserBase with a Profile property.
Customizations
Credentials (Forms authentication)
You can pass custom credentials, derived from ILoginCredential, LoginCredential, or
FormsAuthenticationLoginCredential with the Login call. With custom credentials, you will
generally also want to provide a custom IEntityLoginManager implementation to receive
these credentials. If you wish to take advantage of existing DevForce ASP.NET service
integration, you should derive your class from the AspNetAuthenticatingLoginManager and
override methods as needed.
IEntityLoginManager
You can implement your own IEntityLoginManager or extend the
AspNetAuthenticatingLoginManager to provide custom logic. Any custom implementation
will be used if found.
UserBase
You can also extend the UserBase class. If you enable the ASP.NET Profile service you will
want to use a custom UserBase which contains additional properties retrieved from the
profile. DevForce will automatically return your custom UserBase (if found) without the need
to implement a custom AspNetAuthenticatingLoginManager.
Troubleshooting
"Error using ASP.NET Membership: Unable to connect to SQL Server database."
Message received on a Login call.
This will occur if the ASP.NET membership database cannot be found or opened. You must
configure the ASP.NET membership provider if you wish to use ASP.NET security features,
and by default the AspNetSqlProvider is used. This will use the LocalSqlServer connection
string from either your web.config or the machine.config. The default connection expects a
SQLExpress database named aspnetdb.mdf. For more information on configuring ASP.NET
membership see the membership tutorials at http://www.asp.net/learn/security/ .
The default in the machine.config:
XML <connectionStrings>
<add name="LocalSqlServer" connectionString="data source=
.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;
User Instance=true" providerName="System.Data.SqlClient"/>
</connectionStrings>
To override in your web.config, remove the old connection string and add the new connection
string. Here's a sample re-pointing the connection to the default instance of SQL Server on
the machine:
XML <connectionStrings>
<remove name="LocalSqlServer" />
<add name="LocalSqlServer" connectionString=
"Data Source=.;Initial Catalog=aspnetdb;Integrated Security=True;"
providerName="System.Data.SqlClient" />
</connectionStrings>

Security in the Busines Application Template
To facilitate building secure applications in Silverlight, DevForce provides the Business
Application Visual Studio project templates. These templates provide the same navigation
structure and themes as in standard Silverlight navigation and business templates, but
integrate with DevForce ASP.NET security features. Both C# and VB versions are available.

Overview
These templates provide both user authentication and registration using ASP.NET
Membership, and include sample use of ASP.NET Role and Profile features. The templates
also show how "single sign-on" can be performed in DevForce.
Automatic sign-on
When an application built from the templates starts, the first thing it does is create an
AuthenticationManager. This is a sample implementation of the
IdeaBlade.EntityModel.IAuthenticationManager interface, and provides features to login and
register users. When the application starts it calls AuthenticationManager.LoadUser to
automatically login the user if the application is using Windows authentication, or if the user
has a persistent authentication ticket (the "Keep me signed in" checkbox was checked). If
authenticated, the user's "friendly name" is displayed in the main window.
This "friendly name" is an ASP.NET Profile property. You'll see it defined in both the
web.config:
XML <profile>
<properties>
<add name="FriendlyName" />
</properties>
</profile>
... and in the custom User class which extends the default UserBase:
C#
[DataContract]
public partial class User : UserBase {

/// <summary>
/// Gets and sets the friendly name of the user.
/// </summary>
/// <remarks>
/// This is a Profile-backed property.
/// </remarks>
[DataMember]
public string FriendlyName { get; set; }
..
}
VB
<DataContract>
Partial Public Class User
Inherits UserBase

''' <summary>
''' Gets and sets the friendly name of the user.
''' </summary>
''' <remarks>
''' This is a Profile-backed property.
''' </remarks>
<DataMember>
Public Property FriendlyName() As String
Private ...
End Class
If the user could not be authenticated, then she's logged in as a "guest user", and can either
login or register at any time.
Login
The templates provide Login processing - a window to gather credentials, and logic to submit
those credentials to the EntityServer for authentication. On the server the standard DevForce
AspAuthenticatingLoginManager will authenticate the credentials and return a User
instance.
Here's the Login window (in the Windows 7 theme):

Register
New users may also register. A Registration window allows the user to enter information, and
the template provides the logic to register the user to ASP.NET Membership. Validation of
user-entered information is also provided.
Here's the Registration window (also in the Windows 7 theme):

Single sign-on
Once a user is logged in via the AuthenticationManager, any EntityManager subsequently
created will automatically use the credentials already obtained by the
AuthenticationManager. The credentials aren't actually resubmitted to the EntityServer, but
each EntityManager will use the AuthenticationManager.LinkAuthentication method to obtain
the existing User information, and will not need to call the EntityManager.Login method.


Authorize
To build a secure application, it's not enough to only authenticate our users: we must still
authorize their access to data and services.
Your application may support users with different roles - for example 'Admin' users may have
full privileges, while 'HR' users may only work with information in their department. But you
must also authorize against rogue or malicious users, since in most environments you must
assume that either the client or the transport can be compromised.
DevForce provides role-based security authorization features to help.
Before we dive into a discussion of when and how authorization can be used, let's briefly
review the IPrincipal/IIdentity means of providing role-based authorization. Once logged in,
by default a UserBase (or some custom IPrincipal implementation) is always available to all
client and server code. On the client, the Thread.CurrentPrincipal is set to the logged in user
(except in Silverlight), and the EntityManager.Principal property will return the logged in
user. On the server, the Thread.CurrentPrincipal is also set for the calling user, and all
methods and base classes provide either a Principal argument or property.
Having the principal always available means that both declarative and programmatic
authorization can be performed. We discuss the attributes available for declarative
authorization below, but it's also very easy to programmatically check authorization. For
example, a query or save could include a simple check such as the following:
C# bool isAuthorized = Principal.IsInRole("admin");
VB Boolean isAuthorized = Principal.IsInRole("admin")
Entity-level authorization
When you created your entity model, you may have noticed in the EDM Designer that each
entity type has DevForce properties that govern the ability of the client to query and save:

The CanQuery and CanSave properties translate to ClientCanQuery and
ClientCanSave attributes on the generated Entity class. The "Allow includes" and "Allow
projects" properties combine to determine a ClientQueryPermissions attribute.
Suppose we kept the default values for the two "Allow ..." properties and disabled (made
false) the client's ability to query or save this type. The generated class would look like this:
C#
[IbEm.ClientCanQuery(false)]
[IbEm.ClientCanSave(false)]
public partial class OrderDetail : IbEm.Entity {}
VB
<IbEm.ClientCanQuery(False), IbEm.ClientCanSave(False)>
Partial Public Class OrderDetail
Inherits IbEm.Entity
End Class
Turning off all direct query access may seem a bit draconian but you may have types that
should really only be accessible on the server. Turning off all direct save access can be
particularly useful, since many models have quite a bit of read-only data.
Why would you set CanQuery or CanSave to true? To override the default, which will be
determined by the implementation of the "interceptor", EntityServerQueryInterceptor or
EntityServerSaveInterceptor. (We'll discuss the interceptors in more detail below.) The
default implementations of the interceptors allow all queries and saves, but if you've
implemented custom interceptors you might find it useful to disable all access by default, and
enable it only for entity types as needed.
Remember that each entity is defined as a partial class, making it easy to specify these
attributes with code rather than in the designer. In the partial class you can be more particular
and assign the permissions by role as seen in this example.
C#
[ClientCanQuery(AuthorizeRolesMode.Any, "Admin", "Sales")]
public partial class OrderDetail : IbEm.Entity {}
VB
<ClientCanQuery(AuthorizeRolesMode.Any, "Admin", "Sales")>
Partial Public Class OrderDetail
Inherits IbEm.Entity
End Class
You may also decorate your entities with the RequiresAuthentication and RequiresRoles
attributes. The default interceptors, when authorizing a query or save, will check these
attributes before checking the ClientCanQuery and ClientCanSave
attributes. RequiresAuthentication can be used to ensure that a guest user does not have any
access to the entity, while RequiresRoles functions similarly to ClientCanQuery and
ClientCanSave when used to require the user be a member of all roles specified.
C#
[RequiresAuthentication]
public partial class OrderDetail : IbEm.Entity {}
VB
<RequiresAuthentication>
Partial Public Class OrderDetail
Inherits IbEm.Entity
End Class
A separate topic devoted to securing the query with attributes covers this approach in greater
detail.
Query authorization
The EntityServerQueryInterceptor, discussed in depth in the query life cycle topic, is
responsible for authorizing data retrieval. The interceptor allows you to authorize query
access, add additional filters to a query, and to authorize the query results.
As we saw above, the default interceptor will authorize every query using the authorization
attributes decorating the entity. To customize this behavior, and add additional authorization,
you'll need to create a custom interceptor sub-classing the EntityServerQueryInterceptor.
In your custom interceptor you'll have a chance to:
Override the default authorization - You can disable all retrieval unless specifically enabled
for an entity or query.
Perform programmatic authorization - The interceptor Principal property returns the
IPrincipal from the Login and can be used to check roles, and additional information if a
custom IPrincipal is used.
Add filters to the query - You can inspect and modify the query prior to execution. For
example, maybe a "UK" user can query orders from her country only - here's the place to add
that logic.
Authorize query results - Once the query has executed you have one last chance to look
through the results to determine if the user is authorized to see them.
Through a custom interceptor you can also perform additional logging to audit user access
and capture error details.
Save authorization
The EntityServerSaveInterceptor is responsible for authorizing modifications to data before
they are committed to the data source. The interceptor is discussed in depth in the save life
cycle topic.
As we saw above in the discussion of entity-level authorization, the default interceptor will
authorize every save using the authorization attributes decorating the entity. To customize
this behavior, and add additional authorization, you'll need to create a custom interceptor sub-
classing the EntityServerSaveInterceptor.
In your custom interceptor you'll have a chance to:
Override the default authorization - You can disable all saves unless specifically enabled for
an entity.
Perform programmatic authorization - The interceptor Principal property returns the
IPrincipal from the Login and can be used to check roles, and additional information if a
custom IPrincipal is used.
Customize validation - Instance validation is performed by default, but you can fine tune the
validation performed, and add additional verifiers not included on the client.
Through a custom interceptor you can also perform additional logging to audit user access
and capture error details.
Field-level authorization
You might need to authorize user access to specific properties on an entity. Maybe all your
users have read access to the Employee.Name property, but only users with the "Admin" role
can modify it. There are several techniques within DevForce to control field-level (property-
level) access to data.
Scrub the queried data - You can override the ExecuteQuery method in the
EntityServerQueryInterceptor to "scrub" the queried data before it is sent to the client. Note
you can use this technique only for read-only data, since any modifications to the entity will
cause the scrubbed result to be written to the database. For example:
C#
protected override bool ExecuteQuery() {
bool ok = base.ExecuteQuery();
if (ok) {
if (!this.Principal.IsInRole("Admin")) {
if (Query.ElementType == typeof(Customer)) {
foreach (var customer in this.QueriedEntities.Cast<Customer>()) {
customer.CreditLimit = "***";
}
}
}
}
return ok;
}
VB
Protected Overrides Function ExecuteQuery() As Boolean
Dim ok As Boolean = MyBase.ExecuteQuery()
If ok Then
If Not Me.Principal.IsInRole("Admin") Then
If Query.ElementType = GetType(Customer) Then
For Each customer As var In Me.QueriedEntities.Cast(Of Customer)()
customer.CreditLimit = "***"
Next
End If
End If
End If
Return ok
End Function
Use property interceptors - You can define an interceptor to be called before or after a get or
set, and you can define multiple chained interceptor actions. You can easily define
interceptors via attributes, and you can create them programmatically. Within an
interceptor you can check the EntityManager.Principal to determine the user's identity and
roles. You can also log details on property access. Property interception is generally a client-
side activity, since it's there that most property-level access and changes are performed, as
such, don't overly rely on your property interceptors as a security mechanism. See the
Property interceptors topic for detailed information.
Customize validation - Validation of changes on the server is critical if you require
authorization of property-level changes. Remember that on the server you can add verifiers
not included on the client.
Return part of an entity - Not a true security feature, and like property interceptors a client-
side feature which malicious users can abuse, query projections (either anonymous or into a
type) are a means of limiting a query to only the select properties.
Model new entity types - In your entity model, use views, inheritance, entity splitting and
other modeling features to define entities requiring special access requirements. Maybe
you'll need an Employee entity and a SecureEmployee entity; in doing so you can determine
the properties in each, perform custom validations, and control query and save authorization
by entity type.

RSM authorization
You can and should add authorization checks to your remote server methods too. The
RequiresRoles and RequiresAuthentication attributes can be used on remote methods, and you
can add programmatic authorization. Let's look at a sample method:
C#
[AllowRpc, RequiresRoles("admin")]
public static Object GetNumberOfOrders(IPrincipal principal, EntityManager entityManager,
params Object[] args) {
...
}
VB
<AllowRpc(), RequiresRoles("admin")> _
Public Shared Function GetNumberOfOrders(ByVal principal As IPrincipal, ByVal entityManager As
EntityManager, ByVal ParamArray args As Object()) As Object
...
End Function

Here we've added a RequiresRoles attribute to ensure that only users with the "admin" role will be
able to invoke the method. But notice the principal argument to the method? We could just as
easily use that principal to perform authorization, as shown below.
C#
[AllowRpc]
public static Object GetNumberOfOrders(IPrincipal principal, EntityManager entityManager,
params Object[] args) {
if (!principal.IsInRole("admin")) {
throw new PersistenceSecurityException("Access denied");
}
..
}
VB
<AllowRpc()> _
Public Shared Function GetNumberOfOrders(principal As IPrincipal, entityManager As
EntityManager, ParamArray args As Object()) As Object
If Not principal.IsInRole("admin") Then
Throw New PersistenceSecurityException("Access denied")
End If
...
End Function
POCO authorization
Both declarative and programmatic authorization can be performed with POCO types.
All POCO CRUD methods in a service provider class - for query, insert, update and delete -
can be decorated with the RequiresRoles or RequiresAuthentication attributes to control
access to the method. You can also check the Thread.CurrentPrincipal directly to add
programmatic authorization checks to these methods.
If using a custom EntityServerPocoSaveAdapter, you can add programmatic authorization to
the BeforeSave, InsertEntity, UpdateEntity and DeleteEntity methods.
See the POCO topic for more information.







Additional steps
We've covered the basics of authentication and authorization previously, but there are still
additional steps you can take in building and deploying a secure application. We've broken
these down into configuration-related opportunities - considerations which can be addressed
through the deployment configuration; and coding-relating - additional choices you can make
in your code.


Configuration
Use SSL to secure communications. The default DevForce configuration will automatically
use a secure transport if you specify a URL beginning with https in the objectServer tag. If
your Silverlight application was downloaded via a URL beginning with https, then
communications to the EntityServer will use a secure transport. See here for more
information on configuring SSL in IIS.
Disallow access to the debug log file. In IIS, unless you restrict access, anyone can browse
to your debuglog.xml file and discover much more about your application than you probably
want to share. To see if your debug log is browsable, just point your internet browser to it -
for example http://localhost/badgolf/log/debuglog.xml. Blocking access is easy and there are
many ways to do it; here are a few options: 1) change the logFile path to a secure folder
outside of the IIS application folder, 2) turn off all NTFS permissions to the log folder except
as required by the application pool account to create and append to the file, or 3) disable all
IIS authentications for the folder.
In a client application, you may want to turn off the debug log altogether if it's not possible to
secure the folder.
Use a database account with appropriate privileges. The userid defined in the database
connection string should not be an administrator or DBA account.
Protect the configuration file. You can encrypt configuration sections, such as the
connectionStrings and ideablade.configuration sections, to limit unauthorized access. See
here for more information. (To encrypt the ideablade.configuration section, make sure that
the section definition contains the fully-qualified assembly name.)
Consider encrypting database connections. See here for more information on encrypted
SQL Server connections.
Do not publish service metadata. By default metadata publishing is disabled for DevForce
services. If you enabled it for any reason, be sure to turn it off when you deploy your
application.
Disable anonymous access in IIS if only authenticated users may access your
application.
Do not use a "wide open" client access policy. If you do not support cross domain access,
remove the clientaccesspolicy.xml and/or crossdomain.xml files. If cross domain access is
needed, lock down the access granted. Note that the sample file provided by DevForce is
"wide open" and is intended as a starter sample only.
Coding
Send less detailed error messages to the client. Although during development you want
detailed error messages to help in diagnosing problems, your client applications should not
receive error messages from the server which might contain detailed or sensitive
information. Implement a custom EntityServerErrorInterceptor to examine and optionally
replace the exception to be sent to the client.
Do not store connection strings in a client config file. If the application is an n-tier
application the connection information is unnecessary, as only the EntityServer requires
connection information. In a 2-tier application, consider using a custom
DataSourceKeyResolver, which although not completely secure because your code can be
disassembled, may still be more secure than the .config file.
Encrypt sensitive files. If you save an EntityCacheState or other sensitive information to the
file system or Isolated Storage, consider encrypting it. Here's a sample.
Consider logging for audit purposes.
Consider the entity model exposure. The client application can be easily disassembled to
see the entire generated entity model. Do you really want that User entity exposed? If you
are using custom authentication with your own user database, consider not including these
tables in your entity model, or creating a separate server-only entity model just for
authentication purposes.
Consider WCF security. Depending on the URL, DevForce will default to either non-
secure communications or transport security with SSL. For additional security requirements
you can configure both client and service security using configuration file settings, or by
implementing custom ServiceHostEvents and ServiceProxyEvents classes.
Intercept server exceptions
In production, your client application should not receive error messages from the server which
might contain detailed or sensitive information. You can intercept server exceptions to
examine and optionally replace the exception to be sent to the client.
EntityServerErrorInterceptor
Implement a custom EntityServerErrorInterceptor to intercept exceptions thrown on the
server. With the OnError method of the interceptor you'll have an opportunity to inspect all
exceptions - thrown by login, queries, saves, and unhandled exceptions from RPC methods.
The default interceptor writes a trace message of the the full exception text to the log, but
does not modify the original exception. To avoid sending sensitive information to a client
application - for example, when a save fails it might indicate the database table or user - you
can replace the exception to be returned to the client.
Note that you can't entirely "swallow" the exception and return no error to the client. If you
set the exception to null DevForce will send the original exception back to the client.
The error interceptor is easy to implement, simply sub-class the base
EntityServerErrorInterceptor and override the OnError method. Be sure to place your class
in an assembly deployed to the server.
Here's a simple example:
C#
using System;
using IdeaBlade.Core;
using IdeaBlade.EntityModel;
using IdeaBlade.EntityModel.Server;

namespace Samples {

class SampleErrorInterceptor : EntityServerErrorInterceptor {

public override void OnError(ErrorInterceptorArgs args) {

// Log the real exception
TraceFns.WriteLine(string.Format("Error {0} on thread {1} for user {2}",
args.Exception.ToString(), System.Threading.Thread.CurrentThread.ManagedThreadId,
base.Principal.Identity.Name));

// Add more detail if possible:
var ese = args.Exception as EntityServerException;
if (ese != null) {
TraceFns.WriteLine(string.Format("Failure type: {0}, operation type: {1}", ese.FailureType,
ese.OperationType));
}

// If the user is a guest, then scrub the exception.
if (!base.Principal.Identity.IsAuthenticated) {
args.Exception = new ApplicationException("The request could not be completed.");
}
}
}
}
The exception will be wrapped in an EntityServerException when returned to the client, with
the RemoteException information describing your exception. Because the actual exception
you throw is not returned to the client application, you can return any exception type, even it
that type is not defined on the client or is not serializable.
Remember that if you do scrub the exception, the try/catch logic in your client code should be
able to handle it.
Test, log and debug

Test
Last modified on April 28, 2011 17:14
Contents
Testing features in DevForce
o Test data
o Mocks and fakes
o Data source extensions
Additional resources
A discussion on development isn't complete without a mention of testing. We focus here
primarily on unit and integration testing - activities often performed by the developer.


We know that a lot of you still aren't writing unit tests. You say it's too hard, or you don't have
time.
It's no longer hard, since all but express versions of Visual Studio 2010 now contain built-in
unit testing tools, and if you're not happy with those there are free 3rd party tools such as
NUnit, xUnit, and more. Surely you can find a test framework to suit you.
But you don't have the time? Yet you do have time to spend countless hours wading through
your UI and code to isolate a single failing line of code, which could have been easily found
and remedied, or maybe even avoided, if unit tests existed.
We'll offer two pieces of advice:
Design with testability in mind - Are you using MVVM? If so, then creating unit tests for your
view models is easy. Using the Repository pattern? Then a test or fake repository can help.
Write unit tests as you go - Writing unit tests for new code is much easier than trying to add
the tests later. Code coverage will be better, and tooling in Visual Studio 2010 makes creating
test projects and tests easier.
Testing features in DevForce
DevForce can help make testing easier.
Test data
Unit tests shouldn't go to the database, and you don't want to fire up IIS for your EntityServer,
yet you want data for your testing. You also want to refresh the data easily so that the tests
don't corrupt it.
Most of the techniques for creating design time data also apply to unit tests. The
EntityManager can be used in "offline" mode - created without connecting to the
EntityServer, and the DefaultQueryStrategy set to CacheOnly so that no queries are sent to the
server. Data can be loaded from a previously created EntityCacheState; or simple entities
created, and then added or attached to the EntityManager. Your tests can then run queries and
perform property navigation, without requiring a database or potentially asynchronous service
calls.
Mocks and fakes
DevForce provides contextual discovery via the CompositionContext, which is particularly
useful in creating custom fakes and mocks for testing.
Using CompositionContext.Fake and the EntityServerFakeBackingStore, you can test much of
your code without ever touching a database.
Data source extensions
When you're ready to test against a database, you can dynamically target different databases
using data source extensions. You likely use one database during development, and other
databases in your staging, test and production environments. Data source extensions allow
you to easily switch among these databases depending on the environment.
Additional resources
Ward Bell on "The Art of Unit Testing"
Patterns and practices - Many of our patterns and practices for DevForce help with building
more testable components.
MSDN documentation on creating unit tests
Log
Last modified on March 29, 2011 17:08
Contents
The Debug log
o The <logging> element in more detail
Generate custom messages
DevForce always generates tracing messages as it runs, on both client and server. By default
in most environments these messages will be written to a log file. You have control over
whether a log file will be produced and where, write your own messages, and take control
over the logging process.
In an n-tier application the client and server logs contain different messages, since different
activities are performed by each. Although the server log will record the activities (such as
login and fetch) of the clients connected to it, its log is not a consolidation of all client logs.


The Debug log
By default, DevForce will create a file of trace and debug messages in all environments
except the Silverlight client and Azure*, as long as you specify the logFile in the logging
element of the ideablade.configuration section:
XML <logging logFile="DebugLog.xml"/>
Writing to the file system is not supported in Silverlight and Azure, but see the topic on
writing a custom logger for how to implement your own logging.
To disable writing to the log file, set the logFile value to an empty string, or remove the
logging element from the config.
If you don't have an ideablade.configuration section in your config file, or an error prevented
it from loading, DevForce will initialize a default configuration. That default will write a file
named "DebugLog.xml" - to a log sub-folder for a web application, otherwise to the same
folder as the executable.
To change the location of the log file, just include the full path and file name wanted. For
example, to write the log to a folder named "c:\AppLogs" with a name of
"SalesAppLog.xml", set logFile="c:\AppLogs\SalesAppLog.xml". If the folder does not
exist, or lacks write permissions, the application will run but a file will not be created. If the
folder is a sub-folder of the application root folder, use a relative path name, such as
"log\MyLog.xml". Note that a tilde in a relative path name is not supported here.
The <logging> element in more detail
Since we've looked at the <logging> element above, let's look at a few other properties you
can use to control logging.
XML <logging logFile="DebugLog.xml" archiveLogs="false" shouldLogSqlQueries="false" />
Set archiveLogs="true" to archive log files. By default this is off, but when on the previous
log file will be renamed with a timestamp indicating the time the file was archived.
Set shouldLogSqlQueries="true" to write the SQL for all entity queries to the log. This can be
particularly helpful in debugging.
We describe other settings in the discussion of real-time trace viewing.
Generate custom messages
The TraceFns and DebugFns classes (in IdeaBlade.Core) allow you to generate trace and
debug messages from your code. Both TraceFns and DebugFns provide identical behavior,
except that TraceFns calls will always execute, since in Visual Studio .NET projects the
conditional TRACE flag is enabled by default for both release and debug builds. For
example, you can use DebugFns.WriteLine to write diagnostic logging messages wanted only
during testing of debug builds, while TraceFns.WriteLine can be used for the logging of
messages you want in the deployed application.
Use a custom logger
Last modified on March 29, 2011 17:07
You can replace DevForce logging with your own custom logger, or multiple loggers, to take
full control over logging in your application.
The ITraceLogger is a simple interface DevForce will search for (via the
ITraceLoggerProvider), and call the logger's Log method whenever a trace message should be
logged. The Log method, although typed as receiving an Object, generally receives a
TraceMessage, which you can inspect to see where and when the message was generated and
by whom.
The debug log is actually generated by an ITraceLogger implementation, the
TraceFileXmlLogger. If you don't provide your own ITraceLogger implementation, then it's
the TraceFileXmlLogger which is used. If you do provide your own logger, the
TraceFileXmlLogger will not be used.
In Silverlight and Azure, two environments where a debug log is not written, a custom ITraceLogger is
a good way of capturing trace and diagnostic information.
Here's a simple sample, which writes logging messages to the Console. Note that DevForce
has a built-in ConsoleLogger, so if you do want to log to the Console you don't need a custom
logger.
C#
using System;
using IdeaBlade.Core;

namespace Samples {

public class SampleLoggerProvider : ITraceLoggerProvider {

public ITraceLogger GetLogger() {
return new SampleConsoleLogger();
}
}

// Sample logger - note that DevForce supplies a class named ConsoleLogger - this is shown here
// as a sample only.
public class SampleConsoleLogger : ITraceLogger {

/// <summary>
/// Return true if your logger is not thread-safe.
/// </summary>
public bool IsSingleThreaded {
get { return false; }
}

/// <summary>
/// Log the trace message - here we write to the Console.
/// </summary>
/// <param name="message"></param>
public void Log(object message) {
Console.WriteLine(message);
}
}
}
VB
Imports System
Imports IdeaBlade.Core

Namespace Samples

Public Class SampleLoggerProvider
Implements ITraceLoggerProvider

Public Function GetLogger() As ITraceLogger
Return New SampleConsoleLogger()
End Function
End Class

' Sample logger - note that DevForce supplies a class named ConsoleLogger - this is shown here
' as a sample only.
Public Class SampleConsoleLogger
Implements ITraceLogger

''' <summary>
''' Return true if your logger is not thread-safe.
''' </summary>
Public ReadOnly Property IsSingleThreaded() As Boolean
Get
Return False
End Get
End Property

''' <summary>
''' Log the trace message - here we write to the Console.
''' </summary>
''' <param name="message"></param>
Public Sub Log(ByVal message As Object)
Console.WriteLine(message)
End Sub
End Class
End Namespace

Real-time trace viewers
Last modified on April 29, 2011 08:38
Contents
Trace publishing
Trace viewer in Silverlight
Trace viewer utilities
Using a trace viewer in your application
The debug log is a historical record of an application's activities: it always starts when the
application starts, and is continuously appended to. But DevForce also provides several "trace
viewers", components which provide a real-time view of tracing as it occurs.
A trace viewer can be started and stopped at any time, run as a standalone utility or as part of
your application, and view tracing messages from different sources.


Before we launch into a discussion of the trace viewer utilities we need to take a slight detour
and discuss trace "publishing" to help understand how a viewer works and what it can view.
Trace publishing
Trace and debug activity within a DevForce application uses the "publish-subscribe"
metaphor: messages are always published, and any number of subscribers may listen in. This
publishing is generally local to the application itself and a subscriber will listen only for its
own activity.
Except in Silverlight client applications, these messages can also be broadcast, or published,
as part of a "trace publisher" service, to make the messages available to remote subscribers.
(For those interested, the publisher is a WCF service.) By default, the console and Windows
Service versions of the server (ServerConsole.exe and ServerService.exe) publish their
messages. In a web application, the service can be started by calling the following, generally
in the global.asax:
C# IdeaBlade.Core.TracePublisher.LocalInstance.MakeRemotable();
VB IdeaBlade.Core.TracePublisher.LocalInstance.MakeRemotable()
A client application can also publish its trace activity, using the same technique.
As a service, the publisher must have a name and port. The default address in DevForce is
net.tcp://localhost:9922/TracePublisher: where net.tcp is the protocol, 9922 is the port, and
TracePublisher is the service name.
Remember the logging element in the ideablade.configuration? Now we see where some of
the "advanced" properties come into play:
XML <logging logFile="DebugLog.xml" port="9922" serviceName="TracePublisher" />
Both port and serviceName can be modified to override the defaults. You can also override
the defaults when calling MakeRemotable, passing a port number and service name.
Why change the defaults? If multiple applications or services will be publishing trace
messages on the same machine, you must change either the port or service name in order to
provide a unique URL.
Now back to the trace viewers. They will "subscribe" to a publisher to view its
messages. That publisher is usually a service as described above, but it can also be the local
publisher.
How does the ITraceLogger compare with a "subscriber"? The ITraceLogger will only receive
messages from the application it's a part of, it will never automatically receive messages from
another trace publisher. The ITraceLogger also will receive messages throughout the life of the
application, it can't subscribe and unsubscribe.
Trace viewer in Silverlight
A debug log is not generated for a Silverlight client application since writing to the file
system is not supported for browser applications, but tracing and debugging messages are still
generated. You can listen for these messages with a custom ITraceLogger, and you can also
use a simple trace viewer user control sample we provide. The sample viewer, when
"dropped" into an existing window, provides a simple real-time display of tracing and
debugging messages generated on the client.
Note that messages from the server will not be shown by this viewer.
Trace viewer utilities
To use a trace viewer as a standalone executable subscribed to a remote publisher, launch the
executable, either WinTraceViewer.exe or WPFTraceViewer.exe. As you might guess from
the names, these are WinForms and WPF implementations of a viewer with the same basic
functionality. Both utilities can be found in the Tools sub-folder of the DevForce installation.

By default the trace viewer will attempt to subscribe to the well-known address mentioned
above: net.tcp://localhost:9922/TracePublisher. You can, however, subscribe to (and
unsubscribe from) any publisher.
The WPFTraceViewer also accepts a command line argument for the URL of the publisher,
for example:
wpftraceviewer.exe "net.tcp://localhost:9001/mypublisher"
Using a trace viewer in your application
You can also use a trace viewer directly in your Windows application, with the viewer opened
as a new window.
To do so, add a reference to either WPFTraceViewer.exe or WinTtraceViewer.exe (both
available in the Tools folder of the DevForce installation) to your UI project. For example,
right-click the references node in your desired UI project, and select Add Reference. On the
Add Reference dialog, select the Browse tab, then browse to the file and click OK.
To launch the WPF viewer:
C#
IdeaBlade.DevTools.WPFTraceViewer.WPFTraceViewer tv = new
IdeaBlade.DevTools.WPFTraceViewer.WPFTraceViewer();
tv.Show();
VB
Dim tv As New IdeaBlade.DevTools.WPFTraceViewer.WPFTraceViewer()
tv.Show()
... or WinForms:
C#
IdeaBlade.DevTools.TraceViewer.TraceViewerForm tv = new
IdeaBlade.DevTools.TraceViewer.TraceViewerForm();
tv.Show();
VB
Dim tv As New IdeaBlade.DevTools.TraceViewer.TraceViewerForm()
tv.Show()
Both viewers have constuctor overloads which allow the trace publisher URL to be specified,
but by default these viewers will subscribe to the local publisher in the application.
To see this in action see WPF Trace Viewer code sample.
Debug
Last modified on March 23, 2011 15:55
There are a number of resources available to help debug your application and diagnose the
cause of problems when they occur.
Use DebugFns.WriteLine to write your own diagnostic and tracing messages to the DevForce
log.
In Silverlight, implement a custom logger or use the sample trace viewer to capture trace and
debug messages.
Check the debug and trace messages on both client and server! The historical record of your
application processing is normally invaluable to IdeaBlade Support, and can offer many
helpful clues in diagnosing problems.
We can't emphasize this strongly enough - understanding the trace messages DevForce
generates can help you quickly diagnose problems.
If you're curious about the SQL generated for a query (and if you're not you should be, since
the results may surprise you), the shouldLogSqlQueries flag on the <logging> element
controls whether generated SQL is written to the log:
XML <logging logFile="DebugLog.xml" shouldLogSqlQueries="true" />
If you're using SQL Server, learn to use SQL Profiler to capture and review all server activity.
EF Prof, an Entity Framework profiler, is an excellent tool for debugging all database activity
from your application.
If you're using VS 2010 Ultimate, take a spin through Intellitrace.
If you've deployed to Azure and run into problems, both a custom logger and Intellitrace can
be helpful.
Check the Event Viewer. The entityserver writes a few startup messages to the application
Event Log, with a source of "DevForce Object Server". Any problems with initializing the
default debug log will be written to the Event Log, as well as startup messages from the
console and Windows Service servers (ServerConsole.exe and ServerService.exe). These
messages indicate how the services were configured, what the endpoint addresses are, and
any errors encountered.
For communication-related problems in n-tier applications, or just to take a peek on what's
being sent between the client and server, Fiddler is very helpful.
For really difficult problems with n-tier communication problems, the Service Trace Viewer
comes in handy. You can find the utility in the Windows SDK Tools (the executable name is
SvcTraceViewer.exe).

You must first enable diagnostics to use this utility, for example:
XML <configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Information, ActivityTracing">
<listeners>
<add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\temp\ServerConsoleTrace.svclog"/>
</listeners>
</source>
</sources>
</system.diagnostics>
</configuration>
Enable ASP.NET trace information for an IIS-hosted EntityServer to see information on client-
server requests.
Understand logged info
Last modified on March 28, 2011 16:32
Contents
Discovery Part 1
License
Housekeeping
Communications
Discovery Part 2
Login
Fetch and save processing
Exceptions
The messages in the debug log may at first look obscure to you, but once you understand
what's being written, when, and why, they can often help in diagnosing
problems. Understanding "normal" activity is also important, so you know what to look for
when something does go wrong.


Most interesting tracing messages from DevForce are generated at start up. At initialization
the IdeaBladeConfig.Instance is loaded, "probing" occurs, and service communication is
initiated. It's during this time that DevForce does most of its logging about how the
application is configured, and here where you'll find the most useful diagnostic information.
Once processing is underway, DevForce performs little logging of its own actions. Custom
trace and debug messages generated from your application will usually help in understanding
your standard processing and any errors or unexpected situations.
In reading through a log you'll notice that messages aren't always sequential, particularly in
the server log. This is because logged actions can occur on different threads, often
concurrently, and is usually not a cause for concern.
Discovery Part 1
Let's look at discovery, or probing, first.

DevForce uses MEF (the Managed Extensibility Framework) to provide extensibility. One of
the first actions performed is to find the default and custom implementations of various
interfaces and base classes. The default implementations are found in the DevForce
assemblies - for example, if you haven't implemented a custom IEntityLoginManager, we'll
fall back to using one of our defaults.
The first message shows the time probing started and a helpful reminder: if the timestamps
showing when probing starts and completes indicate the process is taking too long, see the
Extend topic for information on how to control this.
The second message tells us that one of our assemblies was added to the "parts" catalog. In
this application several custom interface implementations are defined in the assembly listed,
so it's a good bet that our implementations have been found and will be used when needed. If
you've implemented any custom implementations and don't see one or more messages about
the assemblies being added to the parts catalog, then stop and figure out why; maybe the
assemblies weren't found. If an assembly couldn't be loaded you'll also find that message
here: an assembly load failure is usually due to missing references.
Finally we see when probing completed, and all the assemblies DevForce found. It's worth
examining this list for two reasons: 1) if the list contains a lot of assemblies it's likely the
whole probing process is taking too long and also likely that DevForce really does not need to
know about every assembly; and 2) if the list does not contain an assembly that it should then
the application will likely experience a failure later. DevForce needs to find any assembly
containing your model(s) and your custom implementations and known types, but other
assemblies are usually superfluous and will slow down the initialization process. To fix this,
see the Extend topic.
License
Next, the all-important license message:

Why is this important? If the license information is not found the application won't run at
all. If the license information is incorrect, then functionality may be reduced. It's common
when upgrading your license - say from Express to Universal - that you've neglected to re-
generate the code for your entity model. At run time DevForce uses the license found in the
entity model to determine the functionality provided. If you see in the log that the wrong
license was found, first re-generate your model code and try again. (By "re-generate" we
mean only to either open the EDM Designer and save, or select "run custom tool" for the .tt
file - it's the designer code file which must be re-generated.)
You'll also see a message (not shown here) about whether a "session-agnostic load balancing"
license was found. If you have a Data Center license then load balancing support should be
enabled.
Housekeeping
Now for some housekeeping. You'll see somewhat different messages in different
environments, here we show the EntityServer (hosted in the ASP.NET development server)
and Silverlight.
Entity Server -

Silverlight (note that a trace viewer was used to capture these messages) -

The messages will show how the IdeaBladeConfig was loaded. It's generally loaded from an
ideablade.configuration section found in a .config file (but you can also initialize it in
code). For the EntityServer we see that the section was found in the web.config file, while in
Silverlight we see that an app.config was not found and the default configuration will be used.
Since an app.config is generally not needed in a Silverlight application this is standard. For
any environment, if an error message is logged that the configuration was found but failed to
load, ensure that the xml of the .config is correct.
The DevForce version is logged next. Simple, you think. But we've found that it's very easy
after a DevForce upgrade to re-compile and/or re-deploy the wrong assemblies, or have the
client assemblies at one version and the server assemblies at another. The DevForce version
must be the version you expect, and the version must be the same on both client and server.
Communications
Next, the service/proxy start up information is logged. This information will be different on
client and server, since on the server the WCF services are started, while on the client proxies
to these services are created.
Remember that a single EntityService service is started, and then an EntityServer service for
each data source extension and composition context. If you're not using either data source
extensions or composition contexts, then you'll have only a single EntityServer. Note that
there will be some intervening messages not shown here.


What we see here are the services starting and the endpoint addresses on which the services
listen. In this case we see two endpoints for each service. This is because DevForce will
automatically add an endpoint based on the SupportedClientApplicationType setting. This
setting defaults to "UseLicense", which means that DevForce will create endpoints for
whatever the license allows. In this sample we're using a Universal license, and endpoints
were created for both Silverlight and non-Silverlight clients. Why does Silverlight need its
own endpoints? The communication setup and error handling are a bit different.
XML <serverSettings supportedClientApplicationType="UseLicense" />
In a deployed application you should enable only the endpoints wanted. If your EntityServer will
support only Silverlight clients, there's no reason to add non-Silverlight endpoints too.
Here's the communication start up for a Silverlight client:

We see that proxies were created for the Silverlight endpoint addresses we saw above.
Communication failures are the most common type of initialization problem. Life would be
easy if the cause of every communication failure was neatly written in the logs, but this is
often not the case. Error messages from caught exceptions will be logged, but if a service
cannot be started this can often not be logged, so using other debugging techniques may be
needed. The failure of a service to start is usually caused by an IIS compilation failure or a
configuration problem, and is not logged because the application and DevForce never
start. Also, if you see a mismatch between the service endpoint addresses and the addresses
the client is trying to use, that's always a good indication of why communications are failing.
Discovery Part 2
Scattered throughout the log file we'll also see messages from the CompositionHost, issued
when an interface or base class extensibility point is encountered. Generally these messages
are generated the first time something is probed for, but in some cases you'll see a message for
every attempt.
For any of your custom implementations you need to check that it was found and used. When
not found DevForce will generally use the default implementation, and your application may
not work as wanted.
A message such as the following:

... indicates that DevForce is looking for a custom implementation but didn't find one, while
the message below:

... indicates that DevForce is looking for any custom or default implementation and has found
the default.
Below we see a message when our custom implementation was found:

It's good practice to check the logs, on both client and server, to ensure that all your custom
implementations have been found and used. Remember that different extensibility types may
be probed for on client and server: for example the IEntityLoginManager should be on the
server only, while a ServiceProxyEvents implementation would be on the client only.
Login
Login information won't be recorded until the first user tries to log in. At that time, DevForce
will search for an IEntityLoginManager, and record other information about the
authentication environment.

Above we see that ASP.NET Windows security has been enabled, guest access disabled, and
the standard DevForce ASP.NET login manager is in use.
After the first login, further information on client logins will not be recorded by DevForce. A
custom login implementation may want to record when users log in or out.
Fetch and save processing
Some information will be logged for every query which will go to the data source (note you
will not see these messages in the client log). This isn't the SQL for the query, but a simple
string representation of the EntityQuery.

The first time an entity is encountered for a specific data source, this information will be
logged too. The DataSourceKey must be resolved - through either the connectionStrings,
EdmKeys or code - and the EF metadata found. You'll see either a message that the key was
resolved, or an error concerning the connection string or metadata.
Generally, little information is logged for save processing unless an error occurs. You'll see
probing messages for the EntityServerSaveInterceptor and several other types, but no specific
information is recorded about each save.
Exceptions
On the server, most exceptions are caught and written to the log in their entirety, so checking
the server log for exceptions is usually a good idea. All exceptions occurring during a save
will be logged in the server's log: these exceptions often indicate "normal" processing, for
example concurrency errors. The default EntityServerErrorInterceptor will also log all
exception text for any unhandled error to the server log.

Understand the EntityServerException
Last modified on March 30, 2011 10:59
Contents
Details
Catching the exception
When requests to the EntityServer fail (including query and save requests), the server-side
exception is wrapped in an EntityServerException and sent back to the client. Understanding
the EntityServerException can help in debugging application problems. You may be able to
catch the exception and recover - an option that begins with listening to the
EntityManager.EntityServerError event.


If a request to the EntityServer fails the exception returned to the client application will be
wrapped in an EntityServerException. Your application might receive the base
EntityServerException, or one of the custom sub-types:
EntityManagerSaveException for save failures.
EntityServerConnectionException for a subset of EntityServer connection failures.
LoginException for login failures.
PersistenceSecurityException for a subset of unauthorized access attempts.


Details

While the text of the exception message isn't always helpful, since exceptions can bubble up
through many layers, in not only DevForce but in .NET and other assemblies, you'll often
have to look at other details in the exception to understand the problem.
All EntityServerExceptions will have this information:
FailureType will indicate the general reason for the failure: for example Data will indicate a
query or save failed at the database, while Connection will indicate a communications
failure. There are a handful of other reasons too.
OperationType indicates the operation being performed at the time of failure, for example
Query or Save, among others.
For failures occurring on the EntityServer in an n-tier application the InnerException will
often be empty because that information is not serialized to the client. Instead, several other
properties will contain this information:
RemoteExceptionDetails - The ToString() representation of the original exception.
RemoteExceptionName - The exception class name.
RemoteSource - The source of the original exception.
RemoteStackTrace - The stack trace of the original exception.
If the InnerException is present, drilling down into it and all nested inner exceptions can help
determine the original cause of the failure.
Catching the exception
If you've made a synchronous call the EntityServerException will be thrown, and your
try/catch logic should catch the error. In an asynchronous call, use the Error property of the
operation or event arguments to diagnose the failure. Remember when making an
asynchronous call that if your application should continue running after the failure you should
call MarkErrorAsHandled().
The EntityManager also provides a central error handling facility for
EntityServerExceptions. The EntityServerError event will be raised as a "first chance"
handler for any exceptions before they are thrown. In your event handler you can mark the
exception as handled so that it will not be re-thrown. The handled exception will be returned
to an asynchronous operation, however.
Understand and troubleshoot timeouts
Last modified on April 27, 2011 12:37
Contents
Database / transaction timeouts
o Query
o Saves
Communication timeouts
IIS
There are several timeouts which can affect your application. Learning to understand and
troubleshoot timeouts will help to quickly diagnose and fix problems.


If you've received a "timeout" exception, the first question to ask is "Where is it coming
from?" In a n-tier application the timeout might come from the database server, the
communications infrastructure (WCF), or even IIS. In a 2-tier application not hosted in
ASP.NET, the timeout exception will originate from the database.
Any exception you receive will be an EntityServerException or one of its subtypes.
Database / transaction timeouts
You might receive a database-related timeout during either a query or save.
Query

You receive an EntityServerException with a FailureType of Data and OperationType of
Query. The message itself may be less than helpful, it might say something like "An error
occurred while executing the command definition...", or maybe it will say "Timeout
expired". In a 2-tier application you can drill into the inner exceptions to see the underlying
database exception and message. In SQL Server that will be a
System.Data.SqlClient.SqlException with a message which begins with "Timeout expired." In
an n-tier application, you'll need to check the RemoteExceptionName and
RemoteExceptionDetails to find that information.
To fix this problem, modify the query's CommandTimeout. Every query contains a
CommandTimeout property which you can set to override the provider's default query
timeout value. With SQL Server, that default timeout is 30 seconds.
If the CommandTimeout is sufficient but the transaction timeout is not, you'll get an
EntityServerException with a message stating either "The transaction has aborted" or
"Transaction timeout". In some cases the error message will state "The transaction
associated with the current connection has completed but has not been disposed." The
FailureType is Other in all cases.
By default, queries will use TransactionSettings with a UseTransactionScope option set to
true, which indicates that the query should be wrapped in a TransactionScope. When a
query is wrapped in a TransactionScope then the Timeout value on the
TransactionSettings determines the allowed time for the overall transaction. The
TransactionSettings can be passed with the QueryStrategy or set on the
EntityManager.DefaultQueryStrategy. The default timeout value is 1 minute. If your
query does not require a TransactionScope you can set UseTransactionScope to false.
Saves

You receive an EntityManagerSaveException with a FailureType of Data and an
OperationType of Save. You'll need to drill into the details of the exception to see the
underlying System.TimeoutException with the "Transaction Timeout" message.
You cannot set the command timeout for individual inserts, updates and deletes
performed as part of the save processing. Here only the TransactionSettings.Timeout can
be used to alter the processing timeout. You can set the desired timeout on the
SaveOptions passed from the client, or on the EntityServer with the
TransactionSettings.Default singleton. The default timeout is 1 minute.
You receive an EntityManagerSaveException with a FailureType of Other and an
OperationType of Save. The error message states "The transaction associated with the
current connection has completed but has not been disposed."
This will occur when the outer TransactionScope times out before the inner database
transaction completes. To resolve the problem set a larger timeout value on the
SaveOptions passed from the client, or on the EntityServer with the
TransactionSettings.Default singleton. The default timeout is 1 minute.
Communication timeouts
Most communication-related timeout error messages will state something along the lines of
"The HTTP request to 'http://yourserver/EntityServer.svc' has exceeded the allotted
timeout." If you drill into the exception details you'll usually see a System.TimeoutException
wrapping a System.Net.WebException.
You might get a timeout for any type of request to the EntityServer, and they can occur
regardless of whether the request was synchronous or asynchronous.
The default SendTimeout on the client is 1 minute, and it's this timeout that is most often the
cause of communication timeouts. You can override the default value in two ways - via either
configuration or code. See the advanced configuration topic for more information.
There are additional timeout settings available on both client and server, but they don't often
need to be adjusted from their default values. If you are saving large amounts of data then
you might find that in addition to the client's SendTimeout you also need to adjust the server's
ReceiveTimeout.
In your 2-tier application you obviously don't need to be concerned with communications
exceptions.
IIS
Even when your WCF timeouts seem sufficient, you might receive an exception stating that
"The operation has timed out.". The problem might be in another setting applicable only
when hosting the EntityServer under IIS, the executionTimeout. The default value is 110
seconds, and can be modified via the web.config:
XML
<system.web>
<httpRuntime executionTimeout="110"/>
</system.web>




Configure and deploy
Deploy n-tier
Last modified on March 23, 2011 23:50
In the following sections we'll explore the many options and configuration settings available
to you as you configure and deploy an n-tier application.
In an n-tier DevForce application, the client tier communicates with an EntityServer on a
separate application server tier, and the application server in turn communicates with the data
tier.
The client tier
The typical DevForce n-tier client is a smart .NET UI such as a Silverlight, Windows
Presentation Foundation (WPF), or Windows Forms application, but it might also be a
console application, a Windows Service, or an ASP.NET application.
We discuss configuration and deployment of Silverlight and other application types
separately.
The typical DevForce n-tier client is a smart .NET UI such as a Silverlight, Windows
Presentation Foundation (WPF), or Windows Forms application, but it might also be a
console application, a Windows Service, or an ASP.NET application.
In an n-tier DevForce application, the client tier communicates with an EntityServer on a
separate application server tier, and the application server in turn communicates with the data
tier.
We'll discuss configuration and deployment of Silverlight and other application types next.
Deploy Silverlight client
Last modified on March 23, 2011 23:52
Contents
Assemblies
Packaging
Configuration
Security
Troubleshooting
o FIPS Compliance
Deployment of your Silverlight application will generally be performed as part of the
deployment of the EntityServer to a web site. We have additional information on configuring
the web site here.


Assemblies
The following assemblies are always required:
IdeaBlade.Core.SL.dll
IdeaBlade.EntityModel.SL.dll
IdeaBlade.Linq.SL.dll
IdeaBlade.Validation.SL.dll
You'll of course also need all of your own client-side assemblies and other files needed by
your application. If you've implemented any custom extensions of DevForce components,
remember that some will be pertinent to only the client or only the server. In these cases,
particularly for server-only components, it's best to deploy these assemblies to only the
appropriate tier.
Packaging
Generally, Visual Studio has taken care of the packaging of your Silverlight application into
one or more deployment packages, but there are a few additional things to consider.
Your Silverlight application will generally have a main XAP, and possibly additional
secondary deployment packages to be downloaded as needed. The DevForce Silverlight
assemblies support Application Library Caching to help reduce XAP size.
You can enable your application to run out-of-browser and automatically update when the
application changes. DevForce supports OOB Silverlight applications, and has additional
offline support.
Since the client browser will usually cache your XAP files, you should ensure that updates to
your application will be seen by your users. There are several ways of ensuring this, but the
easiest might be to append information to the URL for the XAP file to indicate your current
application version. For example:
XML
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%"
height="100%">
<param name="source" value="ClientBin/MySilverlightApp.xap?version=1.0.0" />
.....
</object>
You'll need to ensure that the client browser has the appropriate version of Silverlight
installed, and you may want to customize the Silverlight install experience for your users.
On the server, you'll deploy any XAPs (and ZIPs for ALC-enabled assemblies) to the
ClientBin folder of your web site. You'll also need to ensure that the XAP mime type is
registered in IIS. See http://learn.iis.net/page.aspx/262/silverlight for more information on
registering the mime type for different IIS versions.
Configuration
By default DevForce will assume that the EntityServer is located in the same location from
which the XAP was downloaded. For example, if the XAP for your application was
downloaded from http://myhost/myapp/default.aspx, DevForce will default the service URL
to http://myhost/myapp/EntityService.svc. If your EntityServer is located at this address, then
you won't need an app.config in your Silverlight application.
If you're using SSL and the XAP is downloaded using https, then the default EntityServer address will
also use https.
If your EntityServer is at a different location, or you need to customize the communication
defaults, then you will need to override the DevForce defaults.
If only the location needs to be changed you can include an app.config file in your
application with the appropriate <objectServer> information. Instead of including an
app.config, you can also specify <objectServer> information programmatically by working
directly with the IdeaBladeConfig.Instance when the application starts.
If you need to customize communications (such as timeouts) you can add a
ServiceReferences.ClientConfig file to your application to specify the <system.serviceModel>
information required, or implement a custom ServiceProxyEvents to customize configuration
at run time. (Note that you cannot define the GZip binding extension in the ClientConfig;
DevForce uses this in the default configuraiton to compress all requests to and responses from
the server. If you use a ClientConfig file you will need to add the GZip binding element
programmatically. See this sample for more information.)
For more information on the default configuration and how to customize it, see here.
If your Silverlight application is not at the same location as your EntityServer you will also need to
deploy a clientaccesspolicy.xml file to the server hosting the EntityServer to enable cross domain
access.
Sample Silverlight app.config, ServiceReferences.ClientConfig and policy files are provided
in the deployment snippets.
Security
Remember that a Silverlight application is vulnerable to malicious users. Its code can be
disassembled, its Isolated Storage peered at, and its communications with the application
server tampered with.
See the Security topic for more information on steps you can take to secure your application.
Troubleshooting
See the topic on n-tier troubleshooting for more information.
FIPS Compliance
If your Silverlight application will be served from a web server on which FIPS (Federal
Information Processing Standards) compliance is enforced, you will need to make the
following changes to both the web.config and startup pages.
In the web.config, you must set debug to false when FIPS is enabled. This is true even during
development: you cannot set debug to true with FIPS enabled!
XML
<system.web>
<compilation debug="false">
</system.web>
If you use an .html page instead of an .aspx page to host the Silverlight XAP control, you will
need to delete the following:
XML
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

The application server tier
The Entityserver is responsible for accessing data sources and helping to secure your
application. The EntityManager in the client application makes requests to the EntityServer
whenever querying (when the query can't be satisfied from cache) or saving entities, and to
call custom service methods.
The EntityServer is implemented as several Windows Communication Foundation (WCF)
services and can be deployed in different ways.
The data tier
We don't really have much to say about your database(s) and leave its configuration to you
and your DBA. You should consider security, however, both in terms of connection
information stored in connection strings, access accounts, and transmission
security. DevForce imposes no special requirements on the data tier.
Deploy client application
Last modified on June 30, 2011 17:31
Contents
Files and assemblies
The config file
o Logging
o ObjectServer
Packaging for deployment
Security
A DevForce n-tier client is often a Silverlight, Windows Presentation Foundation (WPF), or
Windows Forms application, but it might also be a console application, a Windows Service,
or an web application. Although deployment differs for these different application types, the
requirements of each are generally the same.


Files and assemblies
The following assemblies are always required:
IdeaBlade.Core.dll
IdeaBlade.EntityModel.dll
IdeaBlade.Linq.dll
IdeaBlade.Validation.dll
You'll usually need your .config file too:
app.config.exe (or web.config)
You'll of course also need all of your own client-side assemblies and other files needed by
your application. If you've implemented any custom extensions of DevForce components,
remember that some will be pertinent to only the client or only the server. In these cases,
particularly for server-only components, it's best to deploy these assemblies to only the
appropriate tier.
You may place the DevForce assemblies in the GAC, although there's generally no
compelling reason to do so, unless you have a large number of DevForce applications
installed and they are all using the same DevForce version.
You do not need to, and in most cases should not, install DevForce to the target machine.
Runtime license information is found in your model assembly and not the registry.
The config file
You do not need the <connectionStrings> (and <edmKeys>) in your client application
(unless you are also directly accessing local resources). Having database connection
information present represents a security vulnerability, easily fixed by removing this
information.
You'll generally use the <ideablade.configuration> section to provide connection information
to the EntityServer and logging information, although neither is strictly necessary.
Logging
You can use the <logging> element to set the file name and location of the debug log, or to
turn logging off altogether. You also might want to archive log files. Generally other logging
attributes are not needed, or used only for debugging purposes.
A typical config file might contain the following logging information:
XML <logging logFile="log\DebugLog.xml" archiveLogs="true" />
... to place the file in a sub-folder named log and archive files automatically.
Also see the Log topic for more information.
ObjectServer
You'll usually use the <objectServer> element to specify the location of the remote
EntityServer and to enable remote communications.
Note that in Silverlight, the <objectServer> element is not required, as DevForce will use the URL
from which the XAP was downloaded to infer the server address.
We say "usually" because you can also specify this information programmatically, by
working directly with the IdeaBladeConfig.Instance when the application starts. Other
options are to use the <system.serviceModel> element to configure communications, or to
implement a custom ServiceProxyEvents to customize configuration at run time. For more
information on how DevForce determines the defaults and how to customize them, see the
advanced configuration topic.
A typical config file might the contain the following to communicate with an IIS-hosted
EntityServer:
XML
<objectServer remoteBaseURL="http://yourserver"
serverPort="80"
serviceName="yourapp/EntityService.svc"
>
<clientSettings isDistributed="true" />
</objectServer>
If your server is using SSL, then it might look something like this instead:
XML
<objectServer remoteBaseURL="https://yourserver"
serverPort="443"
serviceName="yourapp/EntityService.svc"
>
<clientSettings isDistributed="true" />
</objectServer>
... where we've changed the protocol and port information.
If your EntityServer is hosted by either the DevForce-supplied ServerService or
ServerConsole hosts, then it might look something like this instead:
XML
<objectServer remoteBaseURL="http://yourserver"
serverPort="9009"
serviceName="EntityService"
>
<clientSettings isDistributed="true" />
</objectServer>
Note the differences from when your server is hosted under IIS: the serviceName does not
contain the web application name or .svc extension, and the port is usually not port 80. The
port can be any free port that you've configured your server to listen on - we often use port
9009 in our samples (as we did here) but there are no DevForce requirements for this port
number.
Regardless of the host, your client configuration should match the server's configuration. If the
EntityServer is using https, then the client must too. If the server is listening on port 80, then the
client must use that port.
The <serverSettings> are not pertinent to the client application in an n-tier deployment.
Packaging for deployment
The computers on which you deploy the application likely have the .NET Client Profile or full
.NET Framework 4.0 already installed or you will install it as part of your deployment.
Note that an n-tier client application, unlike a two-tier client application, can be deployed with
the .NET Client Profile without additional assemblies. This is because the
IdeaBlade.EntityModel.Server assembly is not deployed with the client application.
Generally client applications are installed via an installer or a ClickOnce deployment.
Security
Remember that a client application can be compromised. Its code can be disassembled, its
configuration, log and other files peered at, and its communications with the application
server tampered with.
See the Security topic for more information on steps you can take to secure your application.
Connect to multiple application servers
Last modified on April 22, 2011 10:17
Contents
Using ServiceKeys
Difference from data source extension and composition context
The default key
On the server
Using a system.serviceModel
An n-tier client application may connect to more than one application server.


In most n-tier applications, the client application needs to communicate with only a single
"host" of the EntityServer services. By "host" we mean the machine name, port, protocol and
application name forming the URL information commonly found in the <objectServer>
element in your configuration file. We can consider each "host" to be a separate application
server.
Communicating with a single application server, to login, and perform queries and saves, is
sufficient for many applications. But DevForce also allows a client application to work with
multiple application servers, both at the same time and as needed based on application
requirements. For example, your client application may need to work with HR services at site
A while also working with payroll services at site B. Or maybe your application will
sometimes connect to a local application server but at other times needs to work with the
server at headquarters. (In all cases the application server is a DevForce EntityServer, not
custom or third party web services.)
When your application needs to work with multiple application servers, you do so through
something called a serviceKey.
Using ServiceKeys
ServiceKeys provide address information for the application servers your client application
may work with. These keys are defined in your configuration file and allow you to specify a
name and address for each application server. The serviceKey provides additional flexibility
in defining the application server over the fixed information in the <objectServer> element.
You choose the serviceKey to use, and thus the application server, when you construct an
EntityManager.
C#
var entityManager = new NorthwindIBEntityManager(new EntityManagerContext(serviceKey:
"foo"));
VB
Dim entityManager = New NorthwindIBEntityManager(New EntityManagerContext(serviceKey :=
"foo"))
That serviceKey name, here we've used the silly name of "foo", tells DevForce to look for a
serviceKey with this name in the configuration file to obtain the address of the application
server. (You can still use the <system.serviceModel> section to define the service endpoints
in advanced configurations, we describe that below.)
Here's the configuration information for the "foo" key:
XML
<objectServer remoteBaseURL="http://www.contoso.com"
serviceName="BigApp\EntityService.svc" serverPort="80" >
<serviceKeys>
<serviceKey name="foo" remoteBaseURL="http://foo.contoso.com"
serviceName="SmallApp\EntityService.svc" serverPort="8080" />
</serviceKeys>
</objectServer>

An EntityManager constructed with this serviceKey will query and save to the application server
located at the http://foo.contoso.com address. Other EntityManagers in the application can
continue to communicate with the default application server at http://www.contoso.com.
Difference from data source extension and composition context
In other topics we've discussed the use of multiple EntityServers. An EntityServer is created
to match the specifics of the requesting EntityManager. If you are using either a data source
extension or custom composition context when you create your EntityManager, then it will
communicate with an EntityServer having those same characteristics. How does this differ
from service keys?
When using either a data source extension or custom composition context your application
will still communicate with the same application server. The address of the EntityService will
be the same, and that EntityService will determine the specific EntityServer to be used.
With a serviceKey, an entirely different application server, and thus EntityService, will be
used. That application server might be on a different machine altogether, or use a different
port or protocol. You can still use data source extensions and/or custom composition contexts
when using a serviceKey.
The default key
When constructing an EntityManager you can provide a serviceKey in the constructor
arguments. By default, if the serviceKey is not provided then DevForce will use the default
key to determine the application server it will use.
The determination of this default is worth noting. Generally the remoteBaseURL and other
<objectServer> attributes will be used to determine the default key. (In Silverlight
applications this information is set for you based on the address the XAP was loaded
from.) If this information isn't defined then the serviceKeys are searched. If a serviceKey
named "default" is found (the search is case-insensitive) then that serviceKey is used as the
default, otherwise the first serviceKey defined is used as the default.
The following are different ways to specify your keys. In each, the default key found by
DevForce will be the same - the one resolving to an address of
http://www.contoso.com/Samples/EntityService.svc.
XML
<objectServer remoteBaseURL="http://www.contoso.com"
serviceName="Samples\EntityService.svc" serverPort="80" >
<serviceKeys>
<serviceKey name="Backup" remoteBaseURL="http://test.contoso.com"
serviceName="OldSamples\EntityService.svc" serverPort="8080" />
</serviceKeys>
</objectServer>

XML
<objectServer>
<serviceKeys>
<serviceKey name="Default" remoteBaseURL="http://www.contoso.com"
serviceName="Samples\EntityService.svc" serverPort="80" />
<serviceKey name="Backup" remoteBaseURL="http://test.contoso.com"
serviceName="OldSamples\EntityService.svc" serverPort="8080" />
</serviceKeys>
</objectServer>

XML
<objectServer>
<serviceKeys>
<serviceKey name="BOS1" remoteBaseURL="http://www.contoso.com"
serviceName="Samples\EntityService.svc" serverPort="80" />
<serviceKey name="Backup" remoteBaseURL="http://test.contoso.com"
serviceName="OldSamples\EntityService.svc" serverPort="8080" />
</serviceKeys>
</objectServer>

On the server
The purpose of ServiceKeys is to allow you to specify the various application servers your
client application may communicate with. But, since it's often easier to copy configuration
information between client and server config files, the server can also use the serviceKeys in
some configurations.
If an EntityServer is deployed as either a console application or Windows service then
DevForce must determine a "base address" for its services. This address is determined based
on the default key logic described above.
Using a system.serviceModel
If you've found you need the full control the <system.serviceModel> configuration section
offers, you can still use it to define endpoints when using serviceKeys. DevForce will look
for endpoint names with the {ServiceKey}_{ServiceName} format. In other words, if your
serviceKey name is "foo", then DevForce will look for endpoints named "foo_EntityService"
and "foo_EntityServer". Note that the bindings do not need to be the same across
serviceKeys, so for instance one application server might use https while another uses http.
XML
<system.serviceModel>
<client>

<!-- Endpoints for the "default" server -->
<endpoint name="EntityService"
address="http://localhost:9009/EntityService.svc/sl"
binding="customBinding" bindingConfiguration="CustomBinding"
contract="IdeaBlade.EntityModel.IEntityServiceContractAsync"
/>

<endpoint name="EntityServer"
address="http://localhost:9009/EntityServer.svc/sl"
binding="customBinding" bindingConfiguration="CustomBinding"
contract="IdeaBlade.EntityModel.IEntityServerContractAsync"
/>

<!-- Endpoints using the "foo" serviceKey -->
<endpoint name="foo_EntityService"
address="http://fooserver:9009/EntityService.svc/sl"
binding="customBinding" bindingConfiguration="CustomBinding"
contract="IdeaBlade.EntityModel.IEntityServiceContractAsync"
/>

<endpoint name="foo_EntityServer"
address="http://fooserver:9009/EntityServer.svc/sl"
binding="customBinding" bindingConfiguration="CustomBinding"
contract="IdeaBlade.EntityModel.IEntityServerContractAsync"
/>
</client>
<bindings>
<customBinding>
<binding name="CustomBinding">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647"
/>
</binding>
</customBinding>
</bindings>
</system.serviceModel>


Server tier
Last modified on April 20, 2011 08:52
In an n-tier DevForce application, the client tier communicates with an EntityServer on a
separate application server tier, and the application server in turn communicates with the data
tier.
The EntityServer is responsible for accessing data sources and helping to secure your
application. The EntityManager in the client application makes requests to the EntityServer
whenever querying (when the query can't be satisfied from cache) or saving entities, and to
call custom service methods.
The EntityServer is implemented as several Windows Communication Foundation (WCF)
services and can be hosted in different ways, as shown below.
Deployment Description
Console
Application
This is perhaps the simplest deployment, and best suited for development purposes. The EntityServer
services are hosted by the ServerConsole.exe application. The services will shutdown when you terminate the
console application.
Windows Service
The EntityServer services may be hosted by a Windows service, installed by the ServerService.exe application.
Once installed, the services can start when the machine boots, and can be started and stopped via the
Windows Services management console.
Internet
Information
Services (IIS)
The most robust deployment of an EntityServer is via IIS. IIS has built-in support for WCF services, and
provides memory management and fault tolerance capabilities. With an IIS deployment, you'll configure a
web site with the appropriate configuration, and the EntityServer will start whenever a client application
connects. The EntityServer might stop and start with more frequency, as IIS manages the process. You'll use
the IIS Manager to configure and manage the deployment.
Windows Azure See our website for more information and a sample deployment.
We'll discuss the details of each deployment in the following sections.
Service or Server?
You've probably seen the name EntityService used throughout these pages. You've seen it in
the <objectServer> element in your config file. You'll see it when you customize WCF
configuration with a <serviceModel> definition. Why are we using this name, yet talking
about the EntityServer here? (And for that matter, why did we label that element
"objectServer"? Well, that's a story for another day.)
There are several components making up the server. The EntityService is a WCF service and
functions as little more than a gateway or simple router: its primary purpose is to inform a
requesting client which EntityServer it will be working with, and to either start that
EntityServer service or ensure it's already running. It's the EntityServer which is responsible
for all persistence and security activities.
You might have multiple EntityServers too, as one is created to match the specifics of the
requesting EntityManager. If you are using either a data source extension or custom
composition context when you create your EntityManager, then it will communicate with an
EntityServer having those same characteristics. In default configurations DevForce will take
care of the details, but this is something to be aware of in more advanced configurations,
where you might directly configure the services via either configuration or code.
Here's a sample of the services you might see when using data source extensions of "A", "B"
and "C".

Deploy to IIS

The most typical, and most robust, deployment of the EntityServer is with Internet
Information Services (IIS).


Hosting the EntityServer WCF services in IIS has several benefits:
IIS provides process activation, health management, and recycling capabilities to increase the
reliability of hosted applications.
Services hosted in IIS use a dynamic compilation model, which simplifies development and
deployment.
Services are deployed and managed like any other type of IIS application.
When the EntityServer is running in ASP.NET Compatibility Mode it can participate fully in the
ASP.NET request lifecycle and use ASP.NET Security features.
IIS Setup
The EntityServer can be hosted on any version of IIS from 5.1 forward. You'll generally use
the IIS Manager (available from Control Panel | Administrative Tools to manage your
application.
Setup follows the same steps you would take for any IIS application. The only DevForce-
specific requirements are:
.NET Framework 4.0
On some older operating systems or versions of IIS you may need to ensure that the WCF
HTTP activation component is correctly installed and registered. See troubleshooting for
more information.
It's usually easiest to use the Visual Studio Package/Publish features to create a deployment
package and deploy your web application to an IIS server supporting web deployment. We
have a walk through with more information and resources.
If you want to do a manual setup, here are the steps (shown in Internet Information Services
Manager for IIS 7.5):
1. On the web server, create a physical directory for your application under the web site root
folder (typically c:\inetpub\wwwroot).
2. Create bin and log folders under the above directory. Note that the log folder is optional; see
below for more information.
3. Create a new IIS application or reuse an existing application.
Be sure to use an application pool which supports .NET Framework 4 and the integrated
pipeline mode.

To add a new application, right click the Default Web Site and choose Add Application. Here
we're creating the "BadGolf" application using the DefaultAppPool.

4. The log folder requires special setup as you'll need to both grant appropriate write
permissions to create the DebugLog.xml, but also secure the file and folder from
unauthorized access by removing read/browsing permissions. You can disable generation of
the DebugLog altogether, but the diagnostics it produces are generally helpful, especially in a
new deployment.
1. The application runs under the identity of the application pool, which will generally
be DefaultAppPool unless you've created a custom application pool. You'll need to
grant this account write permissions to the log folder. In IIS Manager, browse to the
folder, right click and select Edit Permissions and the Security tab, and then edit the
permissions for the account.
2. If the folder is located under the web application folder the DebugLog.xml contents
will be browsable, so you must disable unauthorized access. In IIS Manager, browse
to and select the applications log folder. Click the Authentication icon under the IIS
section, then select Anonymous Authentication and right click to disable. This will
prevent non-authorized persons from examining the applications debug log.
Silveright considerations
If your IIS application will also host the Silverlight application you need to take a few
additional steps.
1. Create a ClientBin folder under the application folder. Copy all XAP and ZIP files used by your
application into this folder.
2. Copy your *.aspx, *.html and Silverlight.js files to the application folder.
3. Ensure that the XAP mime type is registered in IIS. See here for more information on
registering the mime type for different IIS versions.
Additional considerations
To use SSL to encrypt communications you'll need to obtain a certificate and configure the
https binding for your site. Here's more information.
The EntityServer can also use the net.tcp protocol instead of either http or https. You'll need
to setup the Windows Process Activation Service to bind a non-HTTP port to your site. Here's
more information.
If you're deploying to an Internet Service Provider you should know that the EntityServer
requires "full trust". This trust level is not always supported for shared hosting providers.

If using SQL Server Express databases (such as the aspnetdb database used with ASP.NET
security), the advice from Microsoft is: "When deploying applications into production on any
version of IIS, SQL Server Express user instances should not be used." The reason for this is
that SQL Server Express versions 2005 and 2008 both run under the NETWORK SERVICE
account. You will need to change the account identity of the application pool to NETWORK
SERVICE in order to use your express database, and this is not recommended. Alternately,
you can modify the connection string to use SQL authentication. (See Problems with SQL
Server Express user instancing and ASP.net Web Application Projects for more information.)
See the samples for additional steps needed to use Windows authentication.
If deploying to production, make sure to turn off any diagnostics, WCF tracing or debugging
settings. For example, debug compilation will be on by default until disabled:
XML <compilation debug="false">


Files and assemblies
Now it's time to discuss what to put in the folders you've created for the IIS application.
The following assemblies are always required:
IdeaBlade.Core.dll
IdeaBlade.EntityModel.dll
IdeaBlade.EntityModel.Edm.dll
IdeaBlade.EntityModel.Server.dll
IdeaBlade.EntityModel.Web.dll
IdeaBlade.Linq.dll
IdeaBlade.Validation.dll
You'll also need the .config file:
web.config
Optional but strongly encouraged:
global.asax
Optional (and deprecated):
EntityService.svc
EntityServer.svc
If you've developed your application using one of the DevForce supplied n-tier or Silverlight
application Visual Studio templates, then the required files and references were added to your web
project.
You'll of course also need all of your own "server-side" assemblies. These are the assemblies
holding your entity model(s), and any custom extensions you've implemented.
All assemblies should be placed in the bin folder. You may place the DevForce assemblies in
the GAC, although there's generally no compelling reason to do so, unless you have a large
number of DevForce applications installed and they are all using the same DevForce version.
All other files listed above should be placed in the application root folder.
You do not need to, and in most cases should not, install DevForce to the target machine.
Runtime license information is found in your model assembly and not the registry.
Configuration
All configuration information will be in the web.config.
Database connection information
You'll usually need the <connectionStrings> for any databases your application uses. (You
can also use <edmKeys> instead of or in addition to connectionStrings, but they may be
deprecated in the future.)
Remember the credential information in the connection string: if you include a userid and
password you may want to think about encrypting the connection strings section if the server
cannot be secured. If you use Windows integrated security for your database connections, the
account used to access the database will be the application pool identity, which if you aren't
using a custom application pool will be DefaultAppPool. In this case, using a custom
application pool and identity with only the system and database privileges is a good
option. See the security topic for additional information on securing the database.
If you are using a SQL Server Express database (for ASP.NET security for example),
consider instead deploying the database to a standard SQL Server instance for improved
security.
If you are using a custom DataSourceKeyResolver to dynamically provide connection
information, you will not need to define connection information in the config file.
Logging
You can use the <logging> element to set the file name and location of the debug log, or to
turn logging off altogether. You also might want to archive log files. Generally other logging
attributes are not needed, or used only for debugging purposes.
Logging on the server is usually a good idea, since the diagnostics provided will help during testing
and in resolving deployment problems. In IIS you must take extra precautions to secure the log file.
A typical config file might contain the following logging information:
XML <logging logFile="log\DebugLog.xml" archiveLogs="true" />
... to create a file named DebugLog.xml in the log folder and archive files automatically.
Remember in the IIS Setup above we discussed the special access requirements of the log. In
IIS, unless you restrict access, anyone can browse to your debuglog.xml file and discover
much more about your application than you probably want to share. To see if your debug log
is browsable, just point your internet browser to it - for example
http://localhost/badgolf/log/debuglog.xml.
One final note: do not put the log file in the bin folder. Doing so will cause your assemblies
to be repeatedly recompiled.
Also see the Log and Secure topics for more information.
ObjectServer
Unlike other EntityServer deployments, the service, port and URL information on the
<objectServer> element are not used when hosting in IIS. This is because your IIS
application configuration has already determined the base address(es) to use.
If you've modified any of the defaults for the <serverSettings> element, such as the
allowAnonymousLogin or loginManagerRequired settings, you'll also need to include that
information here. If you're using ASP.NET Security you'll need to include the appropriate
configuration information too.
As an example, your <objectServer> element might have something like the following when
using ASP.NET security and load balancing is required:
XML
<objectServer>
<serverSettings
allowAnonymousLogin="false"
loginManagerRequired="true"
sessionEncryptionKey="mysecretkeyhere"
useAspNetSecurityServices="true"
/>
</objectServer>
A note on load balancing - this is supported with only the Data Center Enterprise
license. You must set the same sessionEncryptionKey on every load-balanced EntityServer
hosting the application to the same non-blank value. The key you use is up to you, but
remember that it functions like a password. If you're planning an Azure deployment with
multiple instances you'll need to set the sessionEncryptionKey.
The <clientSettings> apply only to the client application.
As with any DevForce server or client, you can use a WCF <system.serviceModel>
section to configure communications. See the samples for more information.
Other configuration files
Global.asax
You'll usually include a Global.asax in your application folder. The default generated for you
with the Visual Studio templates registers a "virtual path provider" in the application start
logic. What this does is remove the need for you to provide *.svc files for the various
EntityServer services. The provider instead creates in-memory files on demand.
You can also use the start logic for other actions:
Publish trace messages with a call to
IdeaBlade.Core.TracePublisher.LocalInstance.MakeRemotable(). See the trace viewer topic
for more information.
Control discovery of your entity model and custom components by setting the
IdeaBlade.Core.Composition.CompositionHost.SearchPatterns.
.svc files
You'll notice in the file list above that we called the various *.svc files, such as
EntityService.svc and EntityServer.svc optional. These files, when present, control the
activation of the WCF services comprising the EntityServer. If you've registered the virtual
path provider in the Global.asax as discussed above, then there's no need to have physical
files present, as the provider will create them virtually on demand.
If you don't wish to use the provider or you have customized service activation, then you can
still use the .svc files. You will need a single EntityService.svc file, and one file for each
EntityServer instance your application will use. If you are using either a data source
extension or custom composition context when you create the EntityManager in your client
application, then it will communicate with a specific EntityServer service having those same
characteristics. For example, if you're using a tenant extension of "ABC", you'll need a file
named EntityServer_ABC.svc. The file contents will also need to be customized: see the
samples for more information.
Troubleshooting
WCF is not registered with IIS - See here for information on using ServiceModelReg.
"The login credentials supplied are invalid" when using ASP.NET Forms authentication - If
you've moved your aspnetdb database, or used the database prior to ASP.NET 4.0, the hash
algorithm may have changed. See here for information on setting the machineKey and
hashAlgorithmType.
"Could not load file or assembly 'App_Web_..." after making a change to one or more of the
files in the application directory. You may have encountered a problem that occurs when
files in the application folder no longer match the compiled version located in the
Temporary ASP.NET Files folder. You can force a rebuild of your application by deleting the
bin folder and then replace it with a copy or by running the aspnet_compiler.exe
command with the -c switch. You can find the command by first browsing to the folder
%SystemRoot%\Microsoft.NET\Framework\ and then open the v4.0.xxxxx subfolder (the
numbers after v4.0 can vary). Here is an example using the virtual directory name of the
application: aspnet_compiler v /MyApp -c .
Why must CopyLocal be true in Visual Studio?
Actually, it doesn't have to be. CopyLocal must be true only for those assemblies needed by
IIS to compile the web application, so generally this is only IdeaBlade.EntityModel.Web and
IdeaBlade.EntityModel.Server. If you navigate to the service page and an assembly is
missing, you'll see a compilation error explaining the problem.
It is true, however, that when you deploy your application to the web server - where DevForce
will not be installed - that you'll want all required assemblies in the bin subfolder. It's easier
to see which assemblies you'll need to deploy when they're already in your bin folder during
testing, which they will be when CopyLocal is true.
ASP.NET settings
You may need to modify several ASP.NET runtime settings to control the execution timeout
and maximum request size.
The default execution timeout is 110 seconds. If your application experiences
operation timeouts you can modify the executionTimeout setting. The value is specified in
seconds.
The default maximum request size is 4MB. If your client application sends large data packets
to the server, for example if saving many entities or very large entities, increase the
maxRequestLength value. The value is specified in kilobytes.
Here's a sample httpRuntime element with both settings modified from their defaults:
XML
<system.web>
<httpRuntime maxRequestLength="8192" executionTimeout="130" />
</system.web>
Additional Resources
ASP.NET and IIS Configuration
IIS Learning Center
Deploy as console app
The ServerConsole is provided with the DevForce installation to host the EntityServer
services in a console application.


You'll usually use the ServerConsole only during development and testing when your planned
deployment is as a Windows Service. The ServerConsole is a simple utility you can stop and
start as needed during development to test your n-tier application with a remote EntityServer.
The ServerConsole is not intended to be used in production deployments.
Files and assemblies
The following assemblies are always required:
IdeaBlade.Core.dll
IdeaBlade.EntityModel.dll
IdeaBlade.EntityModel.Edm.dll
IdeaBlade.EntityModel.Server.dll
IdeaBlade.Linq.dll
IdeaBlade.Validation.dll
You'll also need the .config file:
ServerConsole.exe.config
You'll of course also need all of your own "server-side" assemblies. These are the assemblies
holding your entity model(s), and any custom extensions you've implemented.
If the ServerConsole is run on your development machine, the required IdeaBlade assemblies
will already be present with the DevForce installation.
Configuration
Did you notice above that the configuration file used here is named
ServerConsole.exe.config? This is because the executable is named ServerConsole.exe and
we're following standard .NET config file naming and discovery conventions. (In Windows
Server 2003, the config file should be named ServerConsole.config.)
The config file will contain most of what's in your app.config file in your client
application. It's usually easiest to copy that file and edit as needed. You can also use the N-
Tier Deployment Tool to create the file for you.
Database connection information
You'll usually need the <connectionStrings> for any databases your application uses. (You
can also use <edmKeys> instead of or in addition to connectionStrings, but they may be
deprecated in the future.)
If you are using a custom DataSourceKeyResolver to dynamically provide connection
information, you will not need to define connection information in the config file.
Logging
You can use the <logging> element to set the file name and location of the debug log, or to
turn logging off altogether. You also might want to archive log files. Generally other logging
attributes are not needed, or used only for debugging purposes.
Logging on the server is usually a good idea, since the diagnostics provided will help during testing
and in resolving deployment problems.
A typical config file might contain the following logging information:
XML <logging logFile="DebugLog.xml" archiveLogs="true" />

... to create a file named DebugLog.xml and archive files automatically.
Also see the Log topic for more information.
ObjectServer
You'll generally use the <objectServer> element to configure the service information for the
EntityServer.
At a minimum you'll have something like the following:
XML
<objectServer remoteBaseURL="http://localhost"
serverPort="9009"
serviceName="EntityService"
>
</objectServer>
If you've modified the defaults for either allowAnonymousLogin or loginManagerRequired
then you'll also need to include a <serverSettings> element with your settings. The
<clientSettings> apply only to the client application.
Note above that we're using port 9009, one you often see in DevForce samples, but there are
no DevForce requirements for this port number, and you can pick any free port. You should,
however, not change the service name.
You will usually need to allow the ServerConsole to communicate through your firewall on
the port you've chosen. For example, in Windows Firewall the first time you run
ServerConsole.exe from a specific folder and for a particular port number you'll be prompted
to unblock communications to allow the program to accept inbound communications on the
port. You can also manually use your firewall software to open the port wanted, but this is
less secure. See Windows Firewall documentation for more information.
Although we show use of the http protocol above, you can also use net.tcp and https. If using
https you'll need to create an SSL certificate and map it to the port wanted - see this blog for
more information.
As with any DevForce server or client, you can replace the <objectServer> configuration
with a WCF <serviceModel> section which gives you complete control over the
configuration of communications. See the samples.
Using the ServerConsole
All you need to do to use the ServerConsole is place all required files and assemblies in a
folder, along with the ServerConsole.exe and ServerConsole.exe.config, and run the
ServerConsole executable. As noted above you may get a firewall prompt, which you should
accept, and the EntityServer services will start. The console window will display information
about the service configuration, or error information if the service could not start.
You can then run your client application - on the same machine or another machine on the
network. Remember to make sure that its <objectServer> settings match those of the server.
You can terminate the services by closing the window, or pressing either Enter or Ctrl-C
within the window.
Note that by default the ServerConsole "publishes" its trace messages. See the logging topic for more
information.
Using the n-tier starter tool
One of the tools provided in your DevForce installation is a utility called the "N-Tier
Configuration Starter". Such a lofty name for such a simple tool. You can use this utility to
have DevForce create separate Client and Server folders containing the necessary files. The
tool will also create a ServerConsole.exe.config based on your application's config file. See
the walkthrough for more information.
Troubleshooting
You receive an AddressAccessDeniedException telling you that HTTP could not register your
URL because you do not have access rights to the namespace. This is caused because the
executable is not running with administrator privileges and HTTP addresses are secured
resources. You have two options:
1. Run the ServerService with an administrative account.
2. Run the Netsh command line tool to register the namespace with the account. The steps are
as follows:
1. Open a command prompt using Run as administrator and enter:
2. netsh http add urlacl url=http://+:9009/ user=DOMAIN\USERNAME
...where 9009 is the port you are using for the EntityServer, and
DOMAIN\USERNAME is the system account to be granted access.
3. Also see http://blogs.msdn.com/drnick/archive/2006/10/16/configuring-http-for-windows-
vista.aspx for more information.
Deploy as Windows service
The ServerService is provided with the DevForce installation to host the EntityServer as a
Windows service.


Deploying the EntityServer as a Windows service is a good choice in intranet and trusted
domain environments, especially if you're not familiar with IIS.
You'll often find that it's easier to first test with the ServerConsole before deploying the
EntityServer as a Windows service. The ServerConsole configuration and processing are
identical to that of the service, yet the console is easier to setup and to diagnose early
problems.
Files and assemblies
The following assemblies are always required:
IdeaBlade.Core.dll
IdeaBlade.EntityModel.dll
IdeaBlade.EntityModel.Edm.dll
IdeaBlade.EntityModel.Server.dll
IdeaBlade.Linq.dll
IdeaBlade.Validation.dll
You'll also need the .config file:
ServerService.exe.config
You'll of course also need all of your own "server-side" assemblies. These are the assemblies
holding your entity model(s), and any custom extensions you've implemented.
You may place the DevForce assemblies in the GAC, although there's generally no
compelling reason to do so, unless you have a large number of DevForce applications
installed and they are all using the same DevForce version.
You do not need to, and in most cases should not, install DevForce to the target machine.
Runtime license information is found in your model assembly and not the registry.
Configuration
Did you notice above that the configuration file used here is named
ServerService.exe.config? This is because the executable is named ServerService.exe and
we're following standard .NET config file naming and discovery conventions. (In Windows
Server 2003, the config file should be named ServerService.config.)
The config file will contain most of what's in your app.config file in your client
application. It's usually easiest to copy that file and edit as needed.
Database connection information
You'll usually need the <connectionStrings> for any databases your application uses. (You
can also use <edmKeys> instead of or in addition to connectionStrings, but they may be
deprecated in the future.)
Remember the credential information in the connection string: if you include a userid and
password you may want to think about encrypting the connection strings section if the server
on which the ServerService is running cannot be secured. If you use Windows integrated
security, rememeber that the service "log on" account will be the account accessing the
database. Using a custom account for the service with only the system and database
privileges needed is a good option in this case.
If you are using a custom DataSourceKeyResolver to dynamically provide connection
information, you will not need to define connection information in the config file.
Logging
You can use the <logging> element to set the file name and location of the debug log, or to
turn logging off altogether. You also might want to archive log files. Generally other logging
attributes are not needed, or used only for debugging purposes.
Logging on the server is usually a good idea, since the diagnostics provided will help during testing
and in resolving deployment problems.
A typical config file might contain the following logging information:
XML <logging logFile="log\DebugLog.xml" archiveLogs="true" />
... to create a file named DebugLog.xml in the log folder and archive files automatically.
Also see the Log topic for more information. Remember to secure the folder or file from
prying eyes.
ObjectServer
You'll generally use the <objectServer> element to configure the service information for the
EntityServer.
At a minimum you'll have something like the following:
XML
<objectServer remoteBaseURL="http://localhost"
serverPort="9009"
serviceName="EntityService"
>
</objectServer>
If you've modified any of the defaults for the <serverSettings> element, such as the
allowAnonymousLogin or loginManagerRequired settings, you'll also need to include that
information here.
The <clientSettings> apply only to the client application.
Note above that we're using port 9009, one you often see in DevForce samples, but there are
no DevForce requirements for this port number, and you can pick any free port. You should,
however, not change the service name.
Although we show use of the http protocol above, you can also use net.tcp and https. If using
https you'll need to create an SSL certificate and map it to the port wanted - see this blog for
more information.
As with any DevForce server or client, you can replace the <objectServer> configuration
with a WCF <system.serviceModel> section which gives you complete control over the
configuration of communications. See the advanced configuration topic for more
information.
Installing the service
You must first install the ServerService as a Windows service. Do this as follows:
1. Place all required files and assemblies in a folder, along with the ServerService.exe and
ServerService.exe.config
2. Launch the Visual Studio command prompt from the Windows Start menu at Start /
Microsoft Visual Studio 2010 / Visual Studio Tools / Visual Studio Command Prompt.
3. Change to the folder holding your server files and assemblies
4. At the Command Prompt, run the InstallUtil tool as follows:
installutil ServerService.exe
5. After running InstallUtil, the IdeaBlade DevForce 2010 Entity Service will be installed as a
Windows service. You can now start, stop, and configure this service using the Services plug-
in in the Microsoft Management Console (available at Control Panel / Administrative Tools /
Services).

Once the service is running, your client applications can then communicate with the
EntityServer. Remember to make sure that their <objectServer> settings match those of the
server.
Note that by default the ServerService "publishes" its trace messages. See the logging topic for more
information.
Securing the application
You've hopefully taken steps to secure your application, even if it will be used only within
your organization. You've disabled anonymous access, and authorize user actions. Take a
look at the additional steps you can also take.
Troubleshooting
You receive an AddressAccessDeniedException telling you that HTTP could not register your
URL because you do not have access rights to the namespace. This is caused because the
executable is not running with administrator privileges and HTTP addresses are secured
resources. You have two options:
1. Run the ServerService with an administrative account.
2. Run the Netsh command line tool to register the namespace with the account. The steps are
as follows:
1. Open a command prompt using Run as administrator and enter:
2. netsh http add urlacl url=http://+:9009/ user=DOMAIN\USERNAME
...where 9009 is the port you are using for the EntityServer, and
DOMAIN\USERNAME is the system account to be granted access.
3. Also see http://blogs.msdn.com/drnick/archive/2006/10/16/configuring-http-for-windows-
vista.aspx for more information.
Advanced configuration options
Last modified on March 23, 2011 23:59
Contents
N-tier client
o Default configuration
o Customizing configuration
EntityServer
o Default configuration
o Customizing configuration
Controlling compression
Additional resources
The EntityServer is composed of several WCF services. DevForce usually handles the WCF
configuration for you on both client and server, relieving you of the need to understand the
complexities of WCF. But in some circumstances you may want, or need, to take control over
this configuration. Below we'll describe the configuration details and how you can customize
them for advanced scenarios.


N-tier client
By default, DevForce will use the <objectServer> information in your config file to configure
communications from the client to the EntityServer. In Silverlight applications you won't
usually have an app.config file, so the <objectServer> settings are defaulted based on the
URL from which the XAP was downloaded.
You can also directly set objectServer properties on the IdeaBladeConfig.Instance at startup
if you don't wish to use a config file.
Default configuration
Before diving into customization, let's get a better understanding of the default configuration
DevForce uses. The rules are fairly simple:
1. Communications will be established for a specific "service name". This is usually either
"EntityService" or "EntityServer". When a data source extension or custom composition
context is used then the EntityServer name will also contain that information, for example
"EntityServer_dsext+ccname".
2. If a WCF <system.serviceModel> section is found in the config file
(ServiceReferences.ClientConfig in Silverlight) with an endpoint for the particular service
name, then a ChannelFactory is built from this configuration information.
3. If the <system.serviceModel> information was not present or invalid then programmatic
configuration is performed.
1. The Address is built from the information in the <objectServer> element, formatting
a URI from the RemoteBaseUrl, ServerPort and the specific service name. In
Silverlight, "/sl" is appended to the address if not already present, since the default
EntityServer endpoints all use this postfix to indicate Silverlight-specific endpoints.
2. The Binding is built, based on the protocol scheme in the RemoteBaseUrl. A
CustomBinding is built from the following:
1. The GZipMessageEncodingBindingElement to provide compressed binary
messages.
2. A transport binding element appropriate to the protocol:
http - HttpTransportBindingElement
https - HttpsTransportBindingElement
net.tcp - TcpTransportBindingElement. In Silverlight this binding requires the
System.ServiceModel.NetTcp assembly, so DevForce does not provide
programmatic configuration by default; you can still use tcp via the
serviceModel.
net.pipe - NamedPipeTransportBindingElement. Not supported in Silverlight.
3. Whatever the transport, the MaxReceivedMessageSize is set to
int.MaxValue, and except in Silverlight, the ReaderQuotas are set to
int.MaxValue for MaxArrayLength, MaxDepth and
MaxStringContentLength. The ReaderQuotas are not supported by
Silverlight.
3. The Contract is one of the DevForce service contracts, indicating either the
EntityService or EntityServer.
4. The ChannelFactory is built from this information.
4. Except in Silverlight, a DataContractSerializerOperationBehavior is added to all contract
operations to specify the serializer to use (DCS or NDCS).
5. The ServiceProxyEvents OnEndpointCreated and OnFactoryCreated methods are called and
the proxy is opened. See below for more information on the ServiceProxyEvents.
Customizing configuration
We saw above that either the <system.serviceModel> determines the configuration or it's
built programmatically. There are two ways to to customize this.
1. Use the WCF <system.serviceModel> section to configure client communications. See the
samples on working with the serviceModel in client applications.
2. Use a custom ServiceProxyEvents to modify existing configuration. As we saw above,
methods on this class are called after the ChannelFactory is built, regardless of how it is
built. See the samples for a detailed description and examples.
In some cases you may want to use both approaches at the same time. For example, a
<system.serviceModel> to configure the communications elements needed, and then a
ServiceProxyEvents to inject additional runtime-specific behaviors.
In Silverlight, configuration options via the ServiceReferences.ClientConfig are limited, so
doing additional modifications, as permitted by Silverlight, through a ServiceProxyEvents can
be helpful. See the sample on adding Gzip support for an example.
EntityServer
DevForce will create a least two WCF services, one EntityService and one or more
EntityServers. The EntityService functions as a gateway to an EntityServer: a client
application will handshake with it, and then all further communications it makes will be with
an EntityServer. If you are using either a data source extension and/or custom composition
context when you create an EntityManager in your client application, then it will
communicate with an EntityServer service having the same characteristics and whose name
reflects these settings.
Default configuration
The same configuration rules are following for both EntityService and EntityServer
services. Configuration is also independent of hosting type except where noted.
1. Determine the service name. This is usually either "EntityService" or "EntityServer". When a
data source extension or custom composition context is used then the EntityServer name will
also contain that information, for example "EntityServer_dsext+ccname".
2. Determine the base address(es) of the service.
1. When hosted in IIS, the IIS application name and web site bindings determine the
base addresses. For example, if both http and https bindings are enabled for a web
site, then a base address is supplied by IIS for each.
2. When hosted by either the ServiceService or ServerConsole:
1. If <baseAddresses> are defined for the service in the config file then they will
be used,
2. Otherwise information in the <objectServer> element is used, formatting a
URI from the RemoteBaseUrl, ServerPort and the specific service name.
3. If a WCF <system.serviceModel> section is found in the config file with a <service> element
for the particular service name, then it will be used to configure endpoints and
behaviors. For the EntityServer, a service element named "EntityServer" will be used if
present and no element exists for the specific service name (e.g., "EntityServer_ABC"). This
allows the single service configuration to serve as a template for all EntityServer services
which might be used, while still allowing each EntityServer to use custom configuration when
wanted.
4. Add service behaviors:
1. A behavior is added for the DevForce error handler to create DevForce-specific
message faults.
2. Set AspNetCompatibilityRequirementsAttribute to allowed.
3. Add a ServiceThrottlingBehavior to set the MaxConcurrentCalls and
MaxConcurrentSessions to 1000 for http/https and 100 for tcp.
4. Add a DataContractSerializerOperationBehavior to all contract operations to specify
the serializer to use (DCS or NDCS).
5. If no endpoints were found for the service in the <system.serviceModel> then DevForce will
add one or more endpoints for each base address. The SupportedClientApplicationType on
the <serverSettings> determines which endpoints are added. This setting defaults to
UseLicense, which means that endpoints will be added for whatever your license allows.
1. The Address is the base address.
2. The Binding is built based on the protocol scheme for the address. A CustomBinding
is built from the following:
1. The GZipMessageEncodingBindingElement to provide compressed binary
messages.
2. A transport binding element appropriate to the protocol:
http - HttpTransportBindingElement
https - HttpsTransportBindingElement
net.tcp - TcpTransportBindingElement. This is not used for Silverlight
endpoints.
net.pipe - NamedPipeTransportBindingElement. This is not used for
Silverlight endpoints.
3. Whatever the transport, the MaxReceivedMessageSize is set to
int.MaxValue, and the ReaderQuotas are set to int.MaxValue for
MaxArrayLength, MaxDepth and MaxStringContentLength.
3. A ServiceEndpoint is added using the base address, the binding created and the
contract for the service. For Silverlight endpoints, a relative address of "/sl" is added.
4. The ServiceHostEvents OnEndpointCreated is called to allow the endpoint to be
customized.
6. For Silverlight endpoints, an endpoint behavior is added for the SilverlightFaultBehavior to
allow faults to be sent to the Silverlight client. DevForce considers an endpoint a "Silverlight
endpoint" if it contains the "/sl" relative address.
7. After all endpoints are processed ServiceHostEvents OnServiceHostCreated is called to allow
customization of the service and all endpoints before the ServiceHost is opened.
After all these efforts, you'll see messages in the server's log indicating the service name and
the addresses it's listening on. For example, the following log entries show that the
EntityService is listening on four endpoints. Two base addresses were supplied by IIS,
http://myhost/BadGolf and https://myhost/BadGolf becasue both http and https bindings are
set for the web site; and two endpoints were created for each base address, an endpoint for
Silverlight client applications and one for all other applications.

Customizing configuration
We saw above that either the <system.serviceModel> determines the configuration or it's
built programmatically. There are two ways to to customize this.
1. Use the WCF <system.serviceModel> section to configure the service and its endpoints. See
samples on working with the serviceModel on the server.
2. Use a custom ServiceHostEvents to modify existing configuration. As we saw above,
methods on this class are called after each programmatic endpoint is added, and again after
the ServiceHost is built. See the samples for a detailed description and examples.
In some cases you may want to use both approaches at the same time. For example, a
<system.serviceModel> to configure the communications elements needed, and then a
ServiceHostEvents to inject additional runtime-specific behaviors.
As we saw above you can also control the endpoints created using the
SupportedClientApplicationType setting in the <serverSettings>. For example, if your
application will only have Silverlight clients yet you have an Enterprise license, you can set
the appropriate SupportedClientApplicationType setting so that only Silverlight endpoints are
created.
Controlling compression
By default all communications between the n-tier client and EntityServer are
compressed. You can control the level of compression - to prefer speed over compression
factor or vice versa - to fine tune application communications.
To set the compression level, use the CommunicationSettings class. For example:
C#
IdeaBlade.Core.Wcf.Extensions.CommunicationSettings.Default.CompressionLevel =
Ionic.Zlib.CompressionLevel.BestSpeed;
VB

IdeaBlade.Core.Wcf.Extensions.CommunicationSettings.Default.CompressionLevel =
Ionic.Zlib.CompressionLevel.BestSpeed
The CompressionLevel enumeration has a range of possibilities from BestCompression to
BestSpeed. It also supports turning off compression, although if you wish to turn off
compression it's more efficient to change the bindings used.
On the EntityServer the CommunicationSettings.Default.CompressionLevel should be set in
the global.asax when hosted in IIS; on the client you can set this in the application startup
code. You can actually change the CompressionLevel at any time while your application is
running and the new level will be used for all further communications, but generally you
should set this early in your startup logic. The level can also differ between client and server.
Additional resources
The ABCs of Endpoints

Troubleshooting n-tier
Last modified on March 31, 2011 13:24
Contents
Cannot connect to EntityServer
Known type or serializer errors
How to see if the EntityServer is running
Error occurred while trying to make a request ...
Mismatched IdeaBlade assemblies
Also see
An n-tier application is inherently a bit more complex to configure and deploy. Here we'll try
to help with troubleshooting common problems.


Cannot connect to EntityServer
You've received a message such as "The remote server returned an error: NotFound" or
possibly "There is no endpoint listening on http://localhost:9009/EntityService.svc/sl that
could accept calls from this application" (where the address is the address of your
EntityServer). Both messages aren't quite as scary as they sound, and indicate that the client
is unable to communicate with the server, often for a very simple and easily corrected
reason.
You'll usually, but not always, receive additional information with the error message which
attempts to provide some helpful information on the cause of the failure and possible
solutions. Take a moment to read that information to see if it applies.
Also follow these troubleshooting steps:
For Silverlight applications while debugging and testing in Visual Studio, the web project
must be the startup project.
Make sure the service is running.
If you've included a <system.serviceModel> or <objectServer> information in your client
config, make sure that all information is correct, and matches what the server is
using. Double check the address by trying to browse to it to see if the service is running.
Check the debuglog on the server. It will indicate the endpoints the server is listening on.


Known type or serializer errors
Every type which will be moved across tiers must be defined on both tiers, serializable, and a
known type. See the known type primer for more information.
How to see if the EntityServer is running
Regardless of how the EntityServer is hosted, you can always navigate - with your internet
browser - to the "gateway" EntityService. The URL will differ based on the host, but will
generally resemble one of the following:
When hosted in IIS:
http://myserver/myapp/EntityService.svc
In the ASP.NET Development web server (with port 9009):
http://localhost:9009/EntityService.svc
When hosted as a Windows service or console application (again using port 9009 as a
sample):
http://localhost:9009/EntityService
What you see on this page will tell you if the service is running, and if not the error which is
keeping it from running.
Generally, because DevForce does not by default publish metadata, you will see a simple
page that tells you the service is running but publishing is disabled:

You don't need to publish metadata, so seeing this is a good sign, and means the service is
running.
If instead you see any type of "server error" page, then the service has not started. The page
itself will contain diagnostic information on the cause of the problem. For example, here we
see the service did not start because of a bad config file (in this case the xml was invalid).

Whenever your n-tier client application cannot communicate with the EntityServer, the first thing to
check is if the EntityServer is in fact running. Trust us, this will save you, and IdeaBlade Support, a
great deal of time!
Error occurred while trying to make a request ...
If your application is able to connect to the EntityServer but later gets an error such as "An
error occurred while trying to make a request to URI ...", then it's likely that one or more of
the types being sent cannot be serialized for some reason. You'll need to drill into the inner
exceptions to see the original cause. For example, if the error occurs during a SaveChanges, a
custom IIdGenerator will be at fault if it can't be serialized.
Mismatched IdeaBlade assemblies
The IdeaBlade class library versions must be the same on both client and server tiers. If
youve recently upgraded DevForce, you should confirm that the assemblies on both the client
and server have the same version.
Also see
Troubleshooting an IIS Deployment
Troubleshooting a Service or Console Server
Debugging
Known type primer





Two-tier deployment
In a DevForce application, a two-tier deployment is one in which the client tier
communicates directly with the data tier, without the intervention of an application server tier.


This is the simplest of the deployment options, since there are fewer "moving parts" to worry
about. Generally your data tier is on one or more separate physical machines, but it need not
be.
Client application
Without an application server, the responsibilities of the service tier are reduced, and
packaged with the client application. The EntityManager will still communicate with an
EntityServer to authenticate users and query and save entities, but the EntityServer will be
deployed locally, not as a service but as part of the AppDomain in which the application runs.
Your client tier might be a WinForms, WPF or console application, or a Windows
Service. An ASP.NET application which does not require that the EntityServer be exposed as
a service can also be considered a two-tier client application.
Files and assemblies
The following assemblies are always required:
IdeaBlade.Core.dll
IdeaBlade.EntityModel.dll
IdeaBlade.EntityModel.Edm.dll
IdeaBlade.EntityModel.Server.dll
IdeaBlade.Linq.dll
IdeaBlade.Validation.dll
You can use ASP.NET security in a two-tier application. If so, you'll also need:
IdeaBlade.EntityModel.Web.dll
You'll usually need your .config file too:
app.exe.config (or web.config)
You'll of course also need all of your own assemblies and other files needed by your
application.
You may place the DevForce assemblies in the GAC, although there's generally no
compelling reason to do so, unless you have a large number of DevForce applications
installed and they are all using the same DevForce version.
You do not need to, and in most cases should not, install DevForce to the target machine.
Runtime license information is found in your model assembly and not the registry.
The config file
A typical configuration file will contain <connectionStrings> and <ideablade.configuration>
sections, although neither is strictly required.
No part of the <ideablade.configuration> section is required, and can be removed altogether
if you are not using it and can rely on DevForce defaults.
Connection information
You'll usually need the <connectionStrings> for any databases your application uses. (You
can also use <edmKeys> instead of or in addition to connectionStrings, but they may be
deprecated in the future.)
Remember the credential information in the connection string: if you must include a userid
and password you may want to think about encrypting the connection strings section. Using
Windows integrated security is often a better approach.
If you are using a custom DataSourceKeyResolver to dynamically provide connection
information, you will not need to define connection information in the config file.
Logging
You can use the <logging> element to set the file name and location of the debug log, or to
turn logging off altogether. You also might want to archive log files. Generally other logging
attributes are not needed, or used only for debugging purposes.
A typical config file might contain the following:
XML <logging logFile="log\DebugLog.xml" archiveLogs="true" />

... to place the file in a sub-folder named log and archive files automatically.
Also see the Log topic for more information.
ObjectServer
You will not of course be communicating with a remote EntityServer, and frequently the
<objectServer> element is not needed at all. You may find it useful if you wish to modify the
login-related settings for allowAnonymousLogin and loginManagerRequired. Remember that
the config file is not secure, so you may instead want to set these in your application code via
the IdeaBladeConfig.Instance when the application starts.
All other settings for the <objectServer> element and sub-elements are not pertinent to a two-
tier deployment.
Packaging for deployment
The computers on which you deploy the application likely have the .NET Client Profile or full
.NET Framework 4.0 already installed or you will install it as part of your deployment. Note
that a few additional assemblies, not in the .NET Client Profile, are required by DevForce
when deployed in two-tier. This is because the IdeaBlade.EntityModel.Server assembly
references additional assemblies not part of the profile. These are:
System.ServiceModel.Activation
System.ServiceModel.Web.
You should be sure to include these assemblies with your installation.
Generally client applications are installed via an installer or a ClickOnce deployment.

The data tier
We don't really have much to say about your database(s) and leave its configuration to you
and your DBA. You should consider security, however, both in terms of connection
information on the client, access accounts, and transmission security. DevForce imposes no
special requirements on the data tier.
Security
Remember that a client application deployed to a user's workstation can be compromised. Its
code can be disassembled, its configuration, log and other files peered at, and its
communications with the database intercepted.
See the Security topic for more information on steps you can take to secure your client
application.
App.config in detail
DevForce applications are usually configured using an external configuration file - an
app.config for desktop (and sometimes Silverlight) applications, and a web.config for
ASP.NET applications and the EntityServer when hosted by IIS.
With so many .config files in your projects; differences between design-time configuration
and run-time configuration; differences between client and server; and further differences
between development, test and deployed configurations, it's easy to be confused. Here we'll
try to make some sense of these files - what they should contain, and when you should use
them.
Overview
Your first question may be "When do I need to use a .config file?" For now, you should
assume you'll need a .config file whenever you need to override DevForce's default
assumptions. "But what are the DevForce defaults?" you wonder. We'll describe these
defaults below in detail, but generally if you need to tell DevForce something about your
application: "Where is the database? Is there a remote EntityServer? Where? Where is the
log file?" then you will likely need to supply this information via a .config file. You can also
programmatically supply configuration information, and in some cases supply configuration
information via probed interface implementations (e.g., the IDataSourceKeyResolver for
dynamic database connection information is the most common).
If you create your application using one of the DevForce-supplied Visual Studio project
templates, we've included simple .config files where appropriate to get you started. You'll see
a web.config in the web projects of your n-tier solutions, and an app.config in the desktop
projects of both 2-tier and n-tier solutions; these files will contain the necessary information
to get your application running. You'll notice that the Silverlight application does not by
default contain an app.config since it's usually not required, but we'll discuss that further
below.
As you add projects to your solution - for example a class library to hold your Entity Data
Model - you may find these projects also contain an app.config file. In the case of the EDM,
the app.config is used only at design time by the EDM designer. The only configuration files
used at run-time - the only ones DevForce uses - will be the .config for your application
executable and the web.config.
As you develop your application and move from development to test to production
environments your configuration will usually need to change too. For example, log file
locations, database connection strings, the URL of the EntityServer services - all might differ
in the different environments. You'll need to be aware of these changing needs and how to set
configuration appropriate to each environment.
Discovery
Let's jump in and begin with the issue of discovery. DevForce does have some DevForce-
specific features regarding .config discovery, and it's good to understand these features early
to avoid confusion later on.
Silverlight
Unlike standard Silverlight applications in which the app.config (or System.Configuration) is
not supported, DevForce Silverlight applications do support use of an app.config file. Only
the ideablade.configuration section can be specified in the file, since standard Microsoft-
supplied configuration is not supported. (Note the ServiceReferences.ClientConfig file is also
supported in DevForce Silverlight applications for customization of WCF communications.)
DevForce will find the file if placed in the application project, named "app.config", and given
one of the following build actions:
Embedded Resource to embed the file in the assembly
Content to leave the file as a loose file in the XAP, accessible for modification without
recompilation
In most Silverlight applications the default configuration assumed by DevForce is sufficient
and you will not need to supply an app.config at all.
The default configuration assumes that the EntityServer is located in the same location from
which the XAP was downloaded. For example, if the XAP for your application was
downloaded from http://myhost/myapp/default.aspx, DevForce will default the service URL
to http://myhost/myapp/EntityService.svc. If your EntityServer is located at this address, then
you won't need an app.config in your Silverlight application. If your EntityServer is at a
different location, then you will need to override the DevForce default; you can do this by
including an app.config with the appropriate <objectServer> information. Changing the
default with an app.config is optional -- you can also do this programmatically, or via a
ServiceReferences.ClientConfig file.
A sample Silverlight app.config is provided in the deployment snippets available with the
downloaded code.
Desktop / ASP.NET
In non-Silverlight applications, DevForce follows a slightly different probing path to find
the app.config than standard .NET applications. Standard .NET applications use only the
applications config file MyApp.exe.config, or web.config for a web application. In
DevForce, the search for configuration information is as follows, and continues until a valid
configuration is found:
1. If the ConfigFileLocation property of the IdeaBladeConfig object has been set in the executing
code, DevForce will search the indicated location for a file named or matching *.exe.config
(or web.config if a web project). If not found, other *.config files in the folder are searched
for a valid ideablade.configuration section.
IdeaBladeConfig.ConfigFileLocation = @"c:\myapp";
2. If the IdeaBladeConfig.ConfigFileAssembly property has been set, DevForce will look for an
embedded resource named app.config in the specified assembly.
IdeaBladeConfig.ConfigFileAssembly = Assembly.GetExecutingAssembly();
3. Next, the current executable/bin folder is searched for a file named or matching
*.exe.config (or web.config if a web project). If not found, other *.config files in the
folder are searched for a valid ideablade.configuration section.
4. DevForce next searches for an embedded resource named app.config in the entry
assembly.
5. If a valid Ideablade.configuration section was not found in any of the above locations then
DevForce will create a default IdeaBladeConfig instance. In some applications this default
instance may be sufficient, but check your debuglog.xml if you find that your configuration is
not being used.
Caution: If you rely on DevForce-specific discovery - using an embedded resource or a loose
config file not identified by .NET as the config file for the AppDomain - non-IdeaBlade
sections of the config file will not be found by .NET.
Note that in a test project, such as one created with MSTest, if you have enabled deployment
you should also ensure that a loose config file is deployed, or set either
the IdeaBlade.ConfigFileLocation or IdeaBlade.ConfigFileAssembly properties, since
standard DevForce probing may not work as expected.
Configuration contents and defaults
Now that we know how to find a .config file, what should we put in it? DevForce defines the
ideablade.configuration section to hold all IdeaBlade-specific configuration information. At
run-time, this information is used to load the single in-memory instance of
the IdeabladeConfig class, available via the IdeaBladeConfig.Instance static property.
You may modify many properties of the IdeaBladeConfig at run-time, although this should be done
before your application begins using other DevForce features. Programmatic run-time configuration
can be accomplished by modifying IdeaBladeConfig.Instance.
The ideablade.configuration section includes the following child elements.
Element Description
(Root)

objectServer
Governs access to the EntityServer service in an n-tier deployment. Contains
clientSettings and serverSettings child elements to specify configuration
specific to either client or server.
logging Identify where and how to write the DebugLog.
probeAssemblyNames
Deprecated. Allows the developer to specify assemblies to be used in the
discovery of custom implementations of DevForce interfaces. Any assembly
names specified here supplement the default DevForce discovery options.
edmKeys
Optional configuration data applicable to one or more Entity Data Model data
sources. There may be several named <edmKey/> tags if the application uses
more than one Entity Data Model. DevForce will use information in the
<connectionStrings> element to discover data source information, but you
may specify an EdmKey to override that discovery.
verifiers
Used to define verifiers external to your application code. See the Validation
topic for more information.
notificationService Used to define settings for the push notification feature.
Root element
In order to include the ideablade.configuration section in your config file you must "register"
the section. You do this by placing a section element in the configSections, like so:
XML
<configuration>
<configSections>
<section name="ideablade.configuration"
type="IdeaBlade.Core.Configuration.IdeaBladeSection, IdeaBlade.Core" />
</configSections>
</configuration>
The configSections should be at the top of the configuration, so that the section registrations
take place before the actual section.
The ideablade.configuration section looks like the following. It can go anywhere in the
config file after the configSections definitions. Providing the namespace ensures that you can
use Intellisense while editing the config in Visual Studio.
XML
<ideablade.configuration version="6.00"
xmlns="http://schemas.ideablade.com/2010/IdeaBladeConfig">
</ideablade.configuration>
ObjectServer Element
Settings controlling data service features, security, and communications to the EntityServer.
XML
<objectServer remoteBaseURL="http://localhost"
serverPort="9009"
serviceName="EntityService"
useDCS="true" >
<clientSettings isDistributed="false" />
<serviceKeys>
<serviceKey name="BOS2" remoteBaseURL="http://somehost" serverPort="80"
serviceName="myapp/EntityService.svc" />
</serviceKeys>
<serverSettings allowAnonymousLogin="true"
loginManagerRequired="false"
sessionEncryptionKey=""
supportedClientApplicationType="UseLicense"
useAspNetSecurityServices="false"
userSessionTimeout="30"
/>
</objectServer>
Attribute Description
remoteBaseURL The protocol and machine name (or IP address) used to form the full URL.
serverPort The port the EntityServer is listening on.
serviceName
The name of the entry point service. This is generally "EntityService" when not
hosted by IIS; when hosted in IIS the name consists of both the ASP.NET application
name and the service file "EntityService.svc", for example,
"myapp/EntityService.svc".
useDCS
Advanced. Controls the serializer in use for client-server communications in n-
tier. Generally you should not set this field but allow DevForce to choose a
default. In Silverlight applications only "DCS", the DataContractSerializer, may be
used. In Desktop applications, the DCS serializer is also used by default, but you can
instead use the "NDCS", or NetDataContractSerializer, by setting this flag to false.
The remoteBaseURL, serverPort and serviceName attributes are used to determine the
"endpoint" address of the server when running in an n-tier configuration. These settings are
common to both client and server. When running in IIS, or if using a system.serviceModel
section to configure WCF services, you do not need to provide these fields. A full URL,
when built from these fields, might look something like "http://localhost:9009/EntityService"
or "http://localhost/MyApp/EntityService.svc". (Of course "localhost" is used only during
development when both client and server are on the same machine.)
ClientSettings element
The clientSettings apply only to the client. Child element of the objectServer element.
Attribute Description
isDistributed
Determines whether the client will use a remote EntityServer. When enabled, the
client will communicate with an application server tier; when disabled, the client
performs its own data service operations.
ServiceKeys element
The serviceKeys apply to the client, but may be used on the server in some situations as
defined below. A serviceKey provides the address information for a single application server;
a client application may communicate with multiple application servers. Child element of the
objectServer element.
ServiceKey attributes
Attribute Description
name Identifies the service key.
remoteBaseURL The protocol and machine name (or IP address) used to form the full URL.
serverPort The port the EntityServer is listening on.
serviceName
The name of the entry point service. This is generally "EntityService" when not
hosted by IIS; when hosted in IIS the name consists of both the ASP.NET application
name and the service file "EntityService.svc", for example,
"myapp/EntityService.svc".
The remoteBaseURL, serverPort and serviceName attributes are used to determine the
"endpoint" address of a server when running in an n-tier configuration. These attributes serve
the same purpose on the serviceKey as they do when defined on the <objectServer> element
itself. You use one or more <serviceKey> definitions when your client application may
communicate with multiple application servers.
The <serviceKeys> are not usually defined on the server, since their intention is to provide
for multiple named servers, but they can be used there. If the EntityServer is deployed as
either a console application or Windows service then DevForce must determine the "base
address" of the EntityServer. It will use the attributes on the <objectServer> if present,
otherwise it will look for a key named "default", and if not present use the first serviceKey
defined.
ServerSettings element
These settings concern server configuration. In a 2-tier application without an application
server tier you would include any serverSettings needed in the application config file. The
descriptions below indicate if a setting is specific to n-tier. Child element of the objectServer
element.
Attribute Description
allowAnonymousLogin
Determines whether "guest" users are allowed by the
application. These users can use the application without supplying
login credentials. Default is true.
loginManagerRequired
Determines whether the application will function if a "login
manager" cannot be found. When not using ASP.NET security
features you must provide an IEntityLoginManager implementation
if this flag is true. Default is false.
sessionEncryptionKey
In an n-tier application which requires load balancing you must set
this key to a non-blank value. The key is used to encrypt
information in the token passed between client and server. Data
Center license only.
supportedClientApplicationType
This is used in an n-tier application to allow the application server
tier to correctly initialize WCF communications. By default
DevForce will use your license to determine which application types
to support. You may override this setting, as long as the chosen
value is consistent with your license. For example, you might have
a Universal license but a given server might support only Silverlight
clients, or only WinClient clients. By default, if you have a Universal
license communications for both types of clients will be
initialized.
useAspNetSecurityServices
Determines whether ASP.NET security is used for user
authentication. By default this flag is off.
userSessionTimeout
Sets the number of minutes of inactivity after which a client session
is removed from the server's session map. Default is 30 minutes.
Logging Element
Controls the logging of run-time debug and trace information applicable to any configuration.
XML
<logging
logFile="DebugLog.xml"
archiveLogs="false"
shouldLogSqlQueries="false"
port="9922"
serviceName="TracePublisher"
usesSeparateAppDomain="false" />
Attribute Description
logFile
The name of the file containing tracing and debugging information. You
can set the field to an empty string to turn off default logging. You can
also supply a relative or full path name. By default the log file is written to
the exe folder in Desktop applications and to a subfolder named "log" in
ASP.NET applications. Silverlight applications do not create a physical log
file.
archiveLogs Defaults to false. Turn this on to archive previous log files.
shouldLogSqlQueries
Whether to log the generated SQL for queries. This is a global setting
which applies to all data sources. If an EdmKey logTraceString attribute is
false (the default), logging will still occur when shouldLogSqlQueries is
true.
port
This is the port used by the TracePublisher service when "remote"
publishing is enabled. By default port 9922 is used, but if you have
multiple publishers on the same machine you need to provide either a
unique port or serviceName for each.
serviceName
The name of the TracePublisher service when "remote" publishing is
enabled. By default this name is "TracePublisher".
usesSeparateAppDomain
This is an advanced feature which allows the logger to be run in a separate
application domain. By default this value is false and logging takes place
within the same application domain as the publisher.
ProbeAssemblyNames Element
By default DevForce uses MEF (the Managed Extensibility Framework) to discover exported
implementations of custom features. In Silverlight applications, discovery uses the
assemblies in the main XAP. In all other applications, discovery uses the files in the exe/bin
folder. If the default discovery is insufficient you can specify additional assembly names here
to be included when "probing".
It bears repeating if you're familiar with prior DevForce generations: there's generally no reason to
specify the probe assemblies in DevForce 2010. The exception is design time support for the Blend
and Cider designers: if some situations you may need to specify probe assembly names to use some
persistence features such as the EntityCacheState and EntityManager.
XML
<probeAssemblyNames>
<probeAssemblyName name="MyAssembly" />
</probeAssemblyNames>
Sub-element Description
probeAssemblyName
Name of an assembly to be probed. In Silverlight, this should be a fully-
qualified assembly name.
If you do find you need or want to specify the probe assembly names here, there are some
naming rules to be aware of:
In Desktop and ASP.NET applications, you can use the assembly simple name; i.e., the
assembly file name less the .DLL or .EXE extension. For example, for the
DomainModel.dll assembly, use DomainModel.
In Silverlight applications, the assembly display name should be used. The display name
includes the assembly simple name (defined just above), version, culture and public key
token. For example, the assembly display name for the DomainModel.dll assembly might look
like the following:
DomainModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
The public key will be non-null if you have signed the assembly. The version number is the
assembly version defined in your code.
EdmKeys Element
An EdmKey is used to uniquely identify a datasource in DevForce. By default DevForce will
build in-memory EdmKeys based on information in the <connectionStrings> element in the
server's config file. You can specify one or more EdmKeys here to override this behavior. If
the same key name is defined in both the EdmKeys and connectionStrings, the EdmKey
specification will be used.
XML
<edmKeys>
<edmKey
name="Default"
connection="metadata= ....."
tag="some info here"
logTraceString="false"
/>
</edmKeys>
EdmKey attributes
Attribute Description
name
Identifies the data source. If you are using data source extensions the name should
contain the extension. For example a key named "Default_ext1" would be used for
the "ext1" data source extension with the "Default" data source.
connection
The complete EF connection string. This is the same as the connectionString attribute
in the <connectionStrings>.
tag Can be used to provide additional information.
logTraceString
Can be used to enable logging of generated SQL queries. This defaults to false, but
can be turned on when debugging is needed. The shouldLogSqlQueries flag on the
logging element overrides the setting on the EdmKey.
Verifiers Element
Verifiers defined in the .config file are discovered by calling
VerifierEngine.DiscoverVerifiersFromConfig .
XML
<verifiers>
<verifier
name="SampleDateTimeRangeVerifier"
verifierType="IdeaBlade.Validation.DateTimeRangeVerifier, IdeaBlade.Validation"
applicableType="DomainModel.Employee, DomainModel"
executionModes="InstanceAndOnBeforeSetTriggers"
errorContinuationMode="Stop">
<verifierArgs>
<verifierArg name="propertyName" value="BirthDate" />
<verifierArg name="minValue" value="1/1/1965" />
</verifierArgs>
</verifier>
</verifiers>
Verifier attributes
Attribute Description
name Name of the verifier.
description Optional description used in status messages.
verifierType The assembly-qualified name of the verifier
applicableType
The assembly-qualified name of the object type on which the verifier is
defined.
executionModes The conditions under which the verifier will execute.
errorContinuationMode Determines the action to take after a verification error.
sortValue The order in which the verifier will be executed within a verifier batch.
tag Can be used to provide additional information.
verifierArgs Sub-element defining any arguments for the verifier.
VerifierArg attributes
The verifier arguments are specific to the type of verifier.
Attribute Description
name Name of the argument.
value Value of the argument.
NotificationService Element
Used to configure the notification or "push" service.
XML
<notificationService
enabled="false"
clientPort="1001"
/>
Attribute Description
enabled
Defaults to false. This is a server-side setting which allows the Notification Service to be
enabled on the server.
clientPort
Specified in the client-side configuration to indicate the client's port which will receive
pushed messages on the duplex channel. Not applicable to Silverlight clients.
Configuration Editor
So how to edit your app.config or web.config? You can edit directly in Visual Studio, and
Intellisense will help guide you in the elements and attributes available, but if you'd like a
more structured editor we've also provided the DevForce Configuration Editor to help in
editing the ideablade.configuration section. The editor provides descriptive help, and can
eliminate many simple errors such as misspellings. You can use the editor to modify an
existing config file or create a new one.

Customize startup and shutdown
Last modified on March 29, 2011 16:19
Regardless of whether your application is a two-tier application performing its own
persistence operations, or an n-tier application with a separate application server tier, you
might have the need to do some custom processing when the singleton EntityService starts up
and again when it shuts down.
What is the EntityService
We don't often mention the EntityService when discussing the application server tier, but
you've likely seen the name used throughout these pages. You've seen it in the
<objectServer> element in your config file. You'll see it when you customize WCF
configuration with a <serviceModel> definition.
The EntityService functions as little more than a gateway or simple router: its primary
purpose is to inform a requesting client which EntityServer it will be working with, and to
either start that EntityServer or ensure it's already running. It's the EntityServer which is
responsible for all persistence and security activities. These actions occur whether the
application is a standalone application communicating directly with the data tier, or the
EntityServer has been deployed to an application server tier.
The EntityServiceApplication
The IdeaBlade.EntityModel.EntityServiceApplication allows a developer to inject custom
logic when the EntityService starts, and again at shut down.
Here's the simple implementation:
public virtual void OnServiceStartup(object sender, ServiceStartupEventArgs e)
public virtual void OnServiceShutdown(object sender, EventArgs e)
Your custom EntityServiceApplication is found during standard discovery.
At startup, your application might need to launch auxiliary "server-side" processes for
example, or perform other one-time actions.
At shutdown, the application can run "server-side" clean-up code. For example, it might shut
down the auxiliary services it started or send an email alert reporting that the service is
coming down.
Note that you cannot use EntityServiceApplication to customize the WCF configuration. Instead use
the IdeaBlade.EntityModel.Server.ServiceHostEvents for this purpose.
Connect to data sources
You have several options on how your application will connect to the data source. We'll
discuss them here.


Data source keys
DevForce uses the concept of a Data Source Key to identify a data source. The key is used
both at design-time, when the name of the DataSourceKey is tied to the generated code for an
entity model, and again at run time when the EntityManager will query and save entities from
the entity model.
In the EDM Designer
When you created your entity model in the Visual Studio EDM Designer, you specified a
DataSourceKey for the model.

The EntityManager Name and DataSource Key name do not have to be the same. They often are in
samples, since they both default to the Entity Container Name supplied in the EDM Designer.
This key name is also written into the generated code, to associate the entities in a model with
this schema name:
C#
[IbEm.DataSourceKeyName(@"NorthwindIBEntities")]
public partial class Employee : IbEm.Entity { .. }
VB
<IbEm.DataSourceKeyName("NorthwindIBEntities")>
Partial Public Class Employee
Inherits IbEm.Entity
End Class
By default, the DataSourceKey is given the same name as the Entity Container Name, and
thus points to the connection string the designer adds to the config file in your model project:
XML
<connectionStrings>
<add name="NorthwindIBEntities" connectionString="" />
</connectionStrings>
At run time
The EDM Designer created the connection string from a database used at design time. In the
early phases of development, you'll likely use this same database, and connection string, for
your development and testing. As you query and save entities, DevForce uses the
DataSourceKeyName to help find the connection information to the run time database.
The connection information must be in the configuration file used by the EntityServer. If
your entity model was generated into a class library (which is recommended), the app.config
the EDM generated for design-time support won't ever be found or used at run time. So, your
first task is ensuring that you copy or add the connection information to the run time config
file. In an n-tier application, this config file will be on the server, since an n-tier client
application does not directly work with the data tier.
See the topic on config file discovery for more information on how the configuration file is
found at run time.
We're not done yet, though. DevForce uses two pieces of information to find the appropriate
run time connection information: the data source key namecombined with the data source
extension, which we'll discuss next.
Data source extensions
You may not have realized it, but when you constructed your EntityManager you also
supplied it with a data source extension. The default extension is an empty string, meaning of
course that no extension is used. An extension allows an EntityManager to target a specific
run time database: for example it might be instructed to use "Dev" or "Test", or the extension
might indicate that the EntityManager should use the databases for a particular tenant in a
multi-tenant application.
DevForce uses the DataSourceKeyName to identify the data source schema, combined with
the data source extension to indicate the specific schema-matching database to use. It's these
two pieces of information which DevForce uses when searching for the "connection
information" in your configuration file.
For example, if we construct an EntityManager with the "Test" data source extension:
C# manager = new NorthwindEntities(dataSourceExtension: "Test");
VB manager = New NorthwindEntities(dataSourceExtension:= "Test")
DevForce will use the data source key, in this case "NorthwindIBEntities", combined with the
data source extension of "Test" to search the configuration for the best match. But what
specifically is it searching for? We cover that next.
EdmKeys vs. ConnectionStrings
Above we used the vague term "connection information". We did this intentionally, since
there are two ways you can provide connection information to DevForce in a configuration
file:
The first is with connectionStrings. These are the .NET standard way of defining database
connection information in a configuration file. With a connectionString element, you supply
a name and a connectionString containing the appropriate Entity Framework connection
information.
The second method is using a DevForce EdmKey. An edmKey contains connection
information, as a connectionString will, but also additional DevForce attributes, such as
logTraceString, which writes the EF-generated SQL query to the debug log.
In the sample above, DevForce will search for an edmKey or connectionString named
"NorthwindIBEntities_Test". The underscore is the separator character DevForce uses, and
allows you to construct multi-level extensions too. Remember not to use the underscore in
the data source extension you pass into the EntityManager however.
DevForce will search for the best match. If you have both an edmKey and connectionString
with the same name, DevForce will give preference to the edmKey. If DevForce can't find an
exact match, it will drop the last extension from the string and then continue the search, and
so on for all extensions provided. Note that the search is not case sensitive. If a match isn't
found, you'll receive an error when attempting to query or save.
Unless providing connection information dynamically, you must ensure that either an edmKey
or connectionString is available at run time in the appropriate config file.
Dynamic connection strings
DevForce also allows you to omit connection information from the run time configuration
altogether and supply the connection string dynamically, using the
IDataSourceKeyResolver interface.
DevForce actually uses its own implementation of the IDataSourceKeyResolver called the
DefaultDataSourceKeyResolver to perform the key lookup we described above. You can
implement a key resolver to override the default processing.
The IDataSourceKeyResolver interface defines a single method, GetKey, which you'll
implement to provide your own key resolution logic. You should return either an in-memory
EdmKey or ClientEdmKey , or null if you want default key resolution to be performed.
C# IDataSourceKey GetKey(String keyName, String keyExtension, bool onServer);
VB IDataSourceKey GetKey(String keyName, String keyExtension, bool onServer)
Note that the EdmKey you return is constructed only in code and does not need to be defined
in the configuration file.
Although the key resolver is called on both client and server, key resolution is required on
only the server. If you implement a custom resolver it's not required that you deploy your
custom class to the client.
Anatomy of a connection string
Regardless of how you specify your connection information - whether in the
connectionStrings, edmKeys or dynamically - you must still provide a valid Entity Framework
connection string.
Here's an entry defined in the connectionStrings section:
XM
L
<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=.;
Initial Catalog=NorthwindIB;
Integrated Security=True;
MultipleActiveResultSets=True;
&quot;"
providerName="System.Data.EntityClient" />
</connectionStrings>
The <connectionString> has three parts:
name - We discussed the name and how DevForce performs lookup above.
connectionString - The Entity Framework connection string, also consisting of three parts:
o metadata - The location of the metadata artifact files. Note above that an EDMX
named "DomainModel" was used.
o provider - The database provider to use for persistence operations (here it is SQL
Server).
o provider connection string - The provider-specific connection information, usually
indicating the server, database and login information.
providerName - This is the EF provider, and is optional.
Here's the same connection information specified in an EdmKey:
XM
L
<edmKeys>
<edmKey
name="NorthwindIBEntities"
connection="
metadata=res://*/DomainModel.csdl|res://*/DomainModel.ssdl|res://*/DomainModel.
msl;
provider=System.Data.SqlClient;
provider connection string=
&quot;
Data Source=.;
Initial Catalog=NorthwindIB;
Integrated Security=True;
MultipleActiveResultSets=True;
&quot;"
/>
</edmKeys>

As you can see, the connection contains the same information as the connectionString above.
Note that the sample SQL Server connection string above is more common to a developer's
machine than a production deployment.

For more information on connection strings in EF, see http://msdn.microsoft.com/en-
us/library/cc716756.aspx.
Security and connection strings
If you specify your connection information in a .config file, you may want to protect those
sections containing sensitive information. You can encrypt configuration sections, such as the
connectionStrings and ideablade.configuration sections, to limit unauthorized viewing. See
here for more information. (To encrypt the ideablade.configuration section, make sure that
the section definition contains the fully-qualified assembly name.)
In a production deployment, be sure to use a database account with appropriate
privileges. Don't use an administrative account, and if you do use integrated security make
sure that the service account does not have administrative privileges.
Also consider encrypting database traffic. See here for more information on encrypted SQL
Server connections.


You can use the Configuration Editor in two different ways:
1. Launch it from the DevForce 2010 folder in the Windows Start menu.
2. Configure it to work within Visual Studio. To do this:
1. Select the app.config file, right-click, and select Open With option.
2. If you do not see ConfigEditor.exe in the list of programs, click the <Add> button.
3. On the Add Program dialog, click the ellipsis button to browse to a file. Navigate to
the DevForce installation directory (typically C:\Program Files\DevForce 2010) and
select the file ConfigEditor.exe from the Tools subfolder. Give it any Friendly Name
you wish; e.g., DevForce Configuration Editor.
4. Once DevForce Configuration Editor is in the list, double-click it to open the
configuration file in that editor.


Configure programmatically
You can provide DevForce configuration information programmatically by setting
properties of the I deaBladeConfig.I nstance singleton, either on the client or on the server.


Many DevForce components require configuration. A remote client, for example, must be
configured with the address of the server. The DevForce EntityServer needs to know the
connection string of the database.
The "Configure and Deploy" topic describes many ways to provide configuration information
such as adding Ideablade sections to Web.config and App.config files and creating custom
DataSourceKeyResolvers.
This topic describes the IdeaBladeConfig in-memory representation of DevForce
configuration.
IdeaBladeConfig.Instance
At runtime, DevForce creates an in-memory representation of configuration information in a
static "singleton" object called the IdeaBladeConfig.Instance . DevForce components
reference this in-memory singleton when they need configuration data such as
ObjectServer.ClientSettings.IsDistributed: Whether the client is running 2-tier (false) or n-tier
(true)
The URL to the remote server
The Entity Data Model (EDM) keys (EDM Keys) that hold the database connection strings
... much more ...
You can inspect configuration values in your code via the static IdeaBladeConfig.Instance
property. You can update them as we will see.
Both the client application and the server have their own instances of IdeaBladeConfig. They
may share some configuration in common such as the assembly names to probe for custom
classes. Some configuration is meaningful only on the client such as the URL of the server.
Some configuration is meaningful only on the server such as database connection strings. We
use one object type, the IdeaBladeConfig, for both environments.
Client and server functionality execute in the same process in a 2-tier deployment and their
respective configuration data are held in a single IdeaBladeConfig instance.
Where IdeaBladeConfig gets its values
DevForce populates the IdeaBladeConfig from values in the XML configuration file that it
discovers.
It doesn't actually try to populate an IdeaBladeConfig until you or a DevForce component
asks for configuration information.
This just-in-time behavior gives you the ability to specify where to get external configuration
data by setting certain static properties on the IdeaBladeConfig class:
Property Description
ConfigFileLocation Directory to search for configuration files
ConfigFileName Local path and filename of the configuration file to use
ConfigFileAssembly Assembly to search for an embedded
These setting come into play the moment you retrieve the IdeaBladeConfig.Instance.
DevForce discovers the configuration information (if any) and populates the in-memory
IdeaBladeConfig object.
You will notice in the examples below that many of the IdeaBladeConfig object values are not
set at all. That's because DevForce didn't find any pertinent IdeaBlade XML sections in any of
the configuration files it searched.
That's quite normal. When a component requests a configuration value and there is none,
DevForce resorts to default behaviors to discover and construct the unspecified values. We'll
see an example of that below with regard to determining a database connection string.
DevForce prefers configuration values to its own calculated defaults. You can set
configuration values as well as read them. If you set configuration values in the
IdeaBladeConfig object before a component requests them, your custom configuration values
will prevail.
The timing is critical. DevForce components only read IdeaBladeConfig once at the moment
they need a piece of configuration. They stash config away in a place of their convenience
(typically a static field) and don't look back. You must update IdeaBladeConfig before a
DevForce component reads it; otherwise, the horse has left the barn and your updates are
without effect.
If you intend to change the IdeaBladeConfig programmatically, do so very early in the client
application bootstrapping. The Application_Startup method of your Application class is a
good candidate in a WPF or Silverlight app. The Global.asax is a good place for this logic on
the server.
Two-tier client IdeaBladeConfig example
Here's a debugger screenshot of an IdeaBladeConfig in a 2-tier application.

In a 2-tier application, the ObjectServer.ClientSettings.I sDistributed flag is false and remote
URL information is irrelevant (the URL information is null in this example).
Specifying database connections with configuration
Database connection string information is an example of a server side concern. If we want to
specify a connection string in code we can do that in one of the IdeaBladeConfig server-
oriented configuration settings.
The example is taken from a 2-tier IdeaBladeConfig. Because we're focusing on server-side
configuration, the following discussion applies as well to a server-side IdeaBladeConfig in an n-tier
application.
Before explaining how, it's worth noting that database connection strings aren't usually
specified in code. They are typically acquired from XML configuration files.
In the screenshot, the count of the EdmKeys property is zero. Database connection
information is held in EDM Keys. An EDM Key represents connection information about an
Entity Data Model data source (e.g., the database).
There are no EDM Key specifications in the IdeaBladeConfig. Yet the application works; it
retrieves data from the database. Evidently the connection string is coming from somewhere
else. It works because DevForce looks for the connection information in a .NET configuration
file if you don't specify an EDM Key explicitly. Here's the procedure.
When the application queries for an entity, say a Customer entity, DevForce looks up that
entity type's DataSourceName. That name is inscribed in the entity class itself as seen in this
extract from the generated class file:
C#
[IbEm.DataSourceKeyName(@"NorthwindEntities")]
[IbEm.DefaultEntitySetName(@"NorthwindEntities.Customers")]
public partial class Customer : IbEm.Entity { ...
VB
<IbEm.DataSourceKeyName("NorthwindEntities")> _
<IbEm.DefaultEntitySetName("NorthwindEntities.Customers")> _
Partial Public Class Customer Inherits IbEm.Entity ...
Notice that the data source key name is NorthwindEntities.
DevForce sees that you did not specify an EDM Key named NorthwindEntities. Therefore it
looks for a correspondingly-named <connectionStrings/> element inside the appropriate
.NET configuration file: Web.config if the application server runs in IIS; the App.config file in
the application assembly if the application is running 2-tier (as in this example). In either
place, the <connectionStrings/> element looks something like this:

<connectionStrings>
<add name="NorthwindEntities"
connectionString="metadata=res://*/Northwind.csdl|res://*/Northwind.ssdl|res://*/Northwind.m
sl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=localhost;Initial
Catalog=NorthwindIB;Integrated Security=True;MultipleActiveResultSets=True&quot;"
providerName="System.Data.EntityClient" />
</connectionStrings>
The unusual looking connectionString value is an Entity Framework connection string. The first
sections identify the 3 file parts of the EDM; the last section is the database connection string.
<connectionStrings/> is a .NET configuration tag which is why it doesn't appear in the
IdeaBladeConfig object; IdeaBladeConfig only holds DevForce-specific configuration data.
DevForce now has all it needs to dynamically create an EDM Key with the
NorthwindEntities name. You didnt have to specify it explicitly in your configuration.
You COULD have done so in which case your explicit definition would take precedence.
You can specify the EDM Key in the XML configuration file if you wish. But specifying it in
code ... as we do next ... is of greater interest in this IdeaBladeConfig topic.
Specifying database connections in code
If you're not using a configuration file, perhaps you're getting the connection information
from some other external source. Some authors of multi-tenant applications, for example
maintain a central, shared database table with different connection strings for each tenant.
They can add and remove tenants without modifying configuration files and construct the
corresponding EDM Keys on the fly. Most developers would construct such dynamic keys by
means of a custom DataSourceKeyResolver.
Perhaps you have only one or a few connection string and you truly want to bake those strings
directly into your code. There are two simple ways to do it that don't involve a
DataSourceKeyResolver.
The first and preferable way is to add an EDM Key to the IdeaBladeConfig object. Here is an
example that has the same effect as what DevForce did by default, assuming the model and
connections shown above:
C#
var config = IdeaBlade.Core.IdeaBladeConfig.Instance;
var keys = config.EdmKeys;
keys.Add(
new EdmKeyElement
{
Name = "NorthwindEntities",
LogTraceString = false, // whether to log EF generated SQL
// Same connection string as above, tweaked for C#
Connection =
@"metadata=
res://DomainModel.Desktop/Northwind.csdl|
res://DomainModel.Desktop/Northwind.ssdl|
res://DomainModel.Desktop/Northwind.msl;
provider=System.Data.SqlClient;
provider connection string=
'Data Source=localhost;Initial Catalog=NorthwindIB;Integrated
Security=True;MultipleActiveResultSets=True'"
}
);
VB
Dim config = IdeaBlade.Core.IdeaBladeConfig.Instance
Dim keys = config.EdmKeys
keys.Add(New EdmKeyElement With {.Name = "NorthwindEntities", _
.LogTraceString = False, _
.Connection = "metadata=" & ControlChars.CrLf &
"res://DomainModel.Desktop/Northwind.csdl|" _
& ControlChars.CrLf & "res://DomainModel.Desktop/Northwind.ssdl|" & ControlChars.CrLf & _
"res://DomainModel.Desktop/Northwind.msl;" & ControlChars.CrLf & _
"provider=System.Data.SqlClient;" & ControlChars.CrLf & "provider connection string=" _
& ControlChars.CrLf & " 'Data Source=localhost;Initial _
Catalog=NorthwindIB;Integrated Security=True;MultipleActiveResultSets=True'"})
A second way to add the connection string is to add it to the parent configuration's collection
of connection strings as in this example:
C#
var config = IdeaBlade.Core.IdeaBladeConfig.Instance;
// Climb up the configuration tree to get to .NET ConnectionStrings
var connections = config.Configuration.ConnectionStrings.ConnectionStrings;
connections .Add(
new ConnectionStringSettings {
Name = "NorthwindEntities",
// Same connection string as above, tweaked for C#
Connection =
@"metadata=
res://DomainModel.Desktop/Northwind.csdl|
res://DomainModel.Desktop/Northwind.ssdl|
res://DomainModel.Desktop/Northwind.msl;
provider=System.Data.SqlClient;
provider connection string=
'Data Source=localhost;Initial Catalog=NorthwindIB;Integrated
Security=True;MultipleActiveResultSets=True'"
}
);
VB
Dim config = IdeaBlade.Core.IdeaBladeConfig.Instance
' Climb up the configuration tree to get to .NET ConnectionStrings
Dim connections = config.Configuration.ConnectionStrings.ConnectionStrings
' Same connection string as above, tweaked for C#
connections.Add(New ConnectionStringSettings With {.Name = "NorthwindEntities", _
.Connection = "metadata=" & ControlChars.CrLf &
"res://DomainModel.Desktop/Northwind.csdl|" _
& ControlChars.CrLf & "res://DomainModel.Desktop/Northwind.ssdl|" & ControlChars.CrLf _
& "res://DomainModel.Desktop/Northwind.msl;" & ControlChars.CrLf & _
"provider=System.Data.SqlClient;" & ControlChars.CrLf & "provider connection string=" _
& ControlChars.CrLf & " 'Data Source=localhost;Initial _
Catalog=NorthwindIB;Integrated Security=True;MultipleActiveResultSets=True'"})
This approach is generally less useful as you cannot set the LogTraceString which tells
DevForce to log the generated SQL.
Adapting Entity Framework connection strings
The programmatic string is not an exact duplicate of the one that Entity Framework put in the
model project's App.config (or in the Web.config if your model co-habitates with the web
application project). You"ll have to make some adjustments:
make sure to replace the two "&quot;" tokens either with two escaped double quotes (\) or
with single quotes (')
if your model is in a separate project, replace the ( * ) in res://*/ with the model project
assembly's name as in res://DomainModel.Desktop/; if the model project is strongly-named,
you'll have to use the strong name of the assembly.
Setting the server address dynamically: a Silverlight example
Here's a debugger screenshot of an IdeaBladeConfig in a Silverlight client.

Silverlight applications are necessarily n-tier so the
ObjectServer.ClientSettings.I sDistributed flag must be true.
Notice there is no place to specify a connection string. The EDM Keys node is missing from
the Silverlight definition of IdeaBladeConfig. A Silverlight client has no need of EDM Keys
and it would be insecure to deploy database connection strings to a remote client; DevForce
doesn't let you make this mistake.
Other server-only settings such as "UseDCS" are harmless and irrelevant.
You can set the server URL information which has 3 parts as you see in the screenshot:
Property Example Description
RemoteBaseUrl http://localhost Base URL of the server
ServerPort 50501
The port, typically 80 (HTTP) or 443 (HTTPS) in production (prefer
HTTPS!)
ServiceName EntityService.svc
The name of the server-side service; "EntityService.svc" is the
default value and should rarely change.
DevForce combines the parts to form this: http://localhost:5051/EntityServerice.svc. You are
free to devise your own runtime strategy and policies for constructing an alternative remote
server URL. For example, in a developer build, you might display a ComboBox at launch so
the developer/user could pick an appropriate server for that particular launch: a test server, a
stage server, or the production server.
A full .NET n-tier client, written in WPF or Windows Forms or even a Console application,
could do the same.
Take offline
Last modified on May 04, 2011 16:05
DevForces client-side cache enables applications to operate in a partially connected or fully
disconnected environment. You can query, modify, and even create new entities while offline,
and you can save the cache to the file system to preserve the state of the entities if the
application or computer needs to be shut down.
Query entities offline
With a few small exceptions, the same LINQ queries you execute while connected will work
disconnected, except that they will be fulfilled entirely from the client-side cache. While
disconnected, the EntityManager will use a QueryStrategy of CacheOnly for all queries since
the EntityServer is not available. (To learn more about QueryStrategies, see Control query
execution.)
Create, modify, and delete entities offline
Creating and modifying entities is not affected by being disconnected, as these are purely
client-side operations until they are committed to the server by SaveChanges or
SaveChangesAsync. Similarly, you can mark the deletion of an entity while disconnected, and
the EntityState will change to Deleted, but the entity will not be committed until the save.
Connect and Disconnect
You can tell the EntityManager to enter the disconnected state by calling the Disconnect
method. When network access is restored, you can reconnect by calling Connect or
ConnectAsync. While disconnected, the IsConnected property will return false.
If the EntityManager is in the connected state and it experiences a loss of connection, it will:
1. Enter into the disconnected state.
2. Raise the EntityServerError event with an EntityServerConnectionException in the
EntityServerErrorEventArgs, which you should handle and indicate to the user.
3. Throw an EntityServerConnectionException if the EntityServerErrorEventArgs was not marked
as handled in the EntityServerError event.
When creating a new EntityManager while offline, you should pass false for the
shouldConnect parameter. This will keep the EntityManager from automatically attempting to
establish a connection to the entityserver.
Prepare to go offline
Last modified on March 22, 2011 16:18
When you prepare to go offline, you will need to populate the client-side cache with
whatever entities you will need before the database becomes unavailable. To do this, simply
query for the entities that you need and they will automatically be brought into the cache. The
Include operator in LINQ is very handy for this, as it allows you to fetch related entities in a
single query.
For example, if you are caching all of today's Orders, you might also want to fetch the
Customers, OrderDetails, and Products for those orders at the same time:
C#
private void CacheTodaysOrders(EntityManager manager) {
var query = manager.Orders.Where(o => o.OrderDate == DateTime.Today)
.Include("Customer")
.Include("OrderDetails.Products");

query.ExecuteAsync(CacheTodaysOrdersComplete);
}

private void CacheTodaysOrdersComplete(EntityQueryOperation<Order> args) {
}
VB
Private Sub CacheTodaysOrders(ByVal manager As EntityManager)
Dim query = manager.Orders.Where(Function(o) o.OrderDate = Date.Today) _
.Include("Customer") _
.Include("OrderDetails.Products")

query.ExecuteAsync(AddressOf CacheTodaysOrdersComplete)
End Sub

Private Sub CacheTodaysOrdersComplete(ByVal args As EntityQueryOperation(Of Order))
End Sub
If you are caching entities asynchronously, remember to wait for the operation to finish before
going offline! (To learn more about fetching related entities in the same query, see Include
related entities.)
There is no explicit limit to how much you can cache, but eventually memory, serialization,
and query performance may be limiting factors. For large datasets (>50MB), you might
consider using a local database such as SQL Server Express or SQL Server Compact Edition.
(Note that you can create an EntityManager that connects to a local database by passing an
EntityServiceOption of UseLocalService in the constructor.)
Save cache locally
Last modified on April 06, 2011 12:43
Contents
Save and restore
Sample save/restore using Isolated Storage
Save custom properties
Other technical considerations
The EntityManager can serialize or save its cache to a stream or file.


You may want to save cached entities when:
The application must be able to run offline for extended periods, and you need to preserve
the state of the cache if the application or computer is shut down.
The user may accumulate many changes over a long time and you need to backup their data.
This may also occur because the user is not yet ready to commit their changes to the
datastore, or because the modifications to the entities are incomplete, and they might not
pass validation checks required for saving.
Often, especially in Silverlight applications, isolated storage is used to hold the saved data,
but any Stream can be used. For WinClient applications, saving directly to a file is also
available.
Saving to a file is not supported in Silverlight applications.
Save and restore
To access the EntityManager's cache, use its CacheStateManager property. The
CacheStateManager class contains the methods SaveCacheState and RestoreCacheState
which are used to save and load the cache.
Using SaveCacheState, you can save to a stream or file either the entire EntityManager cache
or only a subset of entities.
With RestoreCacheState, you can restore a previously saved cache state into an
EntityManager. When restoring you can also determine the RestoreStrategy to use. The
RestoreStrategy determines how the entities are merged if they already exist in the
EntityManager's cache and whether other default settings on the EntityManager should be
restored.
If you are restoring the cache into an empty EntityManager, then you don't need to worry
about merge conflicts. This only occurs in advanced scenarios where you want to merge the
incoming cache into an already active EntityManager that may have changes you want to
preserve. (For example, you are importing another user's cache, or you are restoring a backup
cache, but want to keep the current modifications.)
In most cases, a RestoreStrategy of Normal is used. This preserves all of the changes in the
EntityManager so that they take precedence in the event of a conflict with the cache being
imported. However, you can configure your own RestoreStrategy if needed. For an in depth
discussion about merging entities see Merge query results into the entity cache.
Both SaveCacheState and RestoreCacheState also allow you to save/restore data in text
format. Binary format is used by default, but text format can be useful when diagnosing
problems or for situations when the serialized data will be used by non-DevForce
applications.
Sample save/restore using Isolated Storage
C#
private void SaveCacheToIsolatedStorage(EntityManager manager, String fileName) {
// Remember to add error handling!
using (var isoFile = IsolatedStorageFile.GetUserStoreForApplication()) {
using (var isoStream = new IsolatedStorageFileStream(fileName, FileMode.Create, isoFile)) {
manager.CacheStateManager.SaveCacheState(isoStream);
}
}
}

private void RestoreCacheFromIsolatedStorage(EntityManager manager, String fileName) {
// Remember to add error handling!
using (var isoFile = IsolatedStorageFile.GetUserStoreForApplication()) {
using (var isoStream = new IsolatedStorageFileStream(fileName, FileMode.Open, isoFile)) {
manager.CacheStateManager.RestoreCacheState(isoStream, RestoreStrategy.Normal);
}
}
}
VB
Private Sub SaveCacheToIsolatedStorage(ByVal manager As _
EntityManager, ByVal fileName As String)
' Remember to add error handling!
Using isoFile = IsolatedStorageFile.GetUserStoreForApplication()
Using isoStream = New IsolatedStorageFileStream(fileName, FileMode.Create, isoFile)
manager.CacheStateManager.SaveCacheState(isoStream)
End Using
End Using
End Sub

Private Sub RestoreCacheFromIsolatedStorage(ByVal manager As _
EntityManager, ByVal fileName As String)
' Remember to add error handling!
Using isoFile = IsolatedStorageFile.GetUserStoreForApplication()
Using isoStream = New IsolatedStorageFileStream(fileName, FileMode.Open, isoFile)
manager.CacheStateManager.RestoreCacheState(isoStream, RestoreStrategy.Normal)
End Using
End Using
End Sub
Save custom properties
If you have defined custom properties on your entity (properties that are not backed by the
datastore and are not calculated) and want these serialized along with the entity, you should
mark them with the DataMember attribute and implement a public get and set for the
property. (Remember to include a reference to the System.Runtime.Serialization assembly.)
C#
[DataMember]
public String Note { get; set; }
VB
<DataMember>
Public Property Note() As String
In addition, by marking the property with the DataMember attribute, the value will also
serialize between the client and EntityServer, so if you set it in one location, it will be
available in the other. You can also serialize complex types.
Other technical considerations
Note that the temporary id map is also serialized to the stream. This allows you to create new
entities without the server (even when connected), and for id fixup to be performed on the
entity graph when the entities are committed to the database. See Custom id generation to
learn more.
When restoring the entity cache, the query cache is also cleared. See Cache a query to learn
more.
The techniques described here can also be used to support both design time data and testing.
Secure offline data
Last modified on March 22, 2011 16:19
If you are working with sensitive data, you will want to make sure to secure the offline data
in case the client computer is compromised.
Encrypt the cache
You should use a CryptoStream to encrypt the cache before saving it to the file system. To
prevent discovery of the encryption key, use a secure hash of the user's credentials (e.g.
username and password) to derive the encryption key and never store the key or password on
the file system where it can be discovered. This way, the serialized cache can only be
decrypted by someone with the correct credentials.
To learn more about encryption, see the SymmetricAlgorithm class.
Authenticate while offline
When offline, there is no host to authenticate the user, and you cannot call the Login or
LoginAsync method. This is ok, since there is no access to the database or other non-local
datasource in this circumstance. To authenticate the user, you can:
1. Check for the successful decryption of the cache which will indicate that they have entered
the correct credentials, or
2. If you are not encrypting the cache, compare the hash of the credentials to the locally stored
hash that was computed from a prior successful login.

Extend
Last modified on March 08, 2011 13:58
DevForce provides a number of extensibility points - interfaces, base types, and attributes -
which allow the developer to specify and customize behaviors.
For example, the application developer can customize login credentials and authentication
processing; intercept the query and save pipelines; control logging; and customize
communication configuration; all through extensibility points within DevForce.
In the following topics we'll discuss what's available and how to control discovery.
Customize
Last modified on March 17, 2011 18:16
Contents
Use DevForce Types
Use DevForce attributes
There are a number of extensibility points within DevForce which allow you to customize
your application processing. We list them here.


The first time DevForce finds and uses your custom classes it will log this fact to the debug
log (or other ITraceLogger implementation). This information, along with logging about all
assemblies loaded into the "parts" catalog, can help in diagnosing problems should they
occur.
Use DevForce Types
The following tables list the DevForce interfaces and base types which you can implement or
extend to provide customization for your application. You'll notice that in some cases there
are default implementations for an interface; in these cases you can either implement the
interface directly or sub-type the base class to provide the customization you require.
Interface Discovery Purpose Topic
IAuthenticationManager Client
Provides credentials to an
EntityManager.
Security
IAuthenticationProvider Client
Provides an
IAuthenticationManager.
Security
ICompositionContextResolver
Client and
Server
Provides for resolution of custom
Composition Contexts.
Discovery
IConcurrencyStrategy Server
Assigns the value of a concurrency
field.
Concurrency
IDataSourceKeyResolver
Client and
Server
Determines the data source key and
connection information.
Data
sources
IEntityLoginManager Server Validates user credentials. Security
IIdGenerator
Client and
Server
Assigns temporary and permanent
IDs for entities.
Custom ids
IKnownType
Client and
Server
Indicates a known type. Known types
IKnownTypeProvider
Client and
Server
Provides programmatic specification
of known types.
Known types
ILoginCredential
Client and
Defines user credentials. Security
Server
ITraceLogger
Client and
Server
A custom logger. Log
ITraceLoggerProvider
Client and
Server
Provides custom logging. Log
IVerifierProvider
Client and
Server
Provides programmatic specification
of verifiers.
Validation
Base Type Discovery Purpose Topic
AspAuthenticatingLoginManager Server
Default IEntityLoginManager when
using ASP.NET security.
Security
BaseCompositionContextResolver
Client and
Server
Default
ICompositionContextResolver
implementation.
Discovery
DefaultConcurrencyValueSetter Server
Default IConcurrencyStrategy
implementation.
Concurrency
DefaultDataSourceKeyResolver
Client and
Server
Default IDataSourceKeyResolver
implementation.
Data
sources
EntityServerErrorInterceptor Server
Intercept and filter exceptions
before sending to the client.
Security
EntityServerPocoSaveAdapter Server
Provides save processing for POCO
classes.
POCO
EntityServerQueryInterceptor Server
Intercept and customize query
processing.
Query
EntityServerSaveInterceptor Server
Intercept and customize save
processing.
Save
EntityServiceApplication Server
Allows for interception of
EntityService events.
Configure
FormsAuthenticationLoginCredential
Client and
Server
ILoginCredential which can be used
with ASP.NET Security.
Security
LoginCredential
Client and
Server
Default ILoginCredential
implementation.
Security
ServiceHostEvents Server
Customize configuration of WCF
services.
Configuration
ServiceProxyEvents Client
Customize configuration of WCF
proxies.
Configuration
UserBase
Client and
Server
Default IPrincipal implementation. Security
UserIdentity
Client and
Server
Default IIdentity implementation. Security
Use DevForce attributes
There are also a few attributes which DevForce will look for to provide specific functionality.
There are other DevForce attributes, such as those for validation, property interception, and
authorization, but we won't list them here since they don't directly relate to the topic of
discoverability and extensibility.
Attribute Discovery Purpose Topic
AllowRpcAttribute Server Indicates an invoked server method.
Server
methods
DiscoverableTypeAttribute
Client and
Server
Indicates a known type. Known types
EnableClientAccessAttribute Server
Indicates a provider of CRUD processing
for POCO classes.
POCO
Discovery
Last modified on April 18, 2011 18:58
Contents
Startup
Controlling discovery
What should be discovered
Discovery, sometimes called probing, is the process DevForce uses to find your entity
models and custom components.


Startup
DevForce uses the Managed Extensibility Framework (MEF) from Microsoft to provide much
of its runtime extensibility. When your application starts, DevForce builds a "parts" catalog
on both client and server containing the customizations it has discovered. By default,
DevForce will check all non-system / non-IdeaBlade assemblies for "exports",
i.e.,implementations of the DevForce interfaces and base types, as well as other components
or your application.
In Silverlight applications, discovery is initially done using the assembly parts in the main XAP.
For modular applications with on-demand download of XAPs DevForce also supports on-
demand discovery.
In Desktop, ASP.NET applications and the EntityServer, discovery uses the assemblies in the
main executable/bin folder.
The CompositionHost manages the discovery process, and provides properties and methods
you can use to modify the default behavior, access the underlying MEF container, and add
dynamic content.
Controlling discovery
In a large application with many assemblies you may find that the discovery performed at
startup takes too long, or maybe you decide there's just no reason to look in assemblies which
will never contain exports or entity models. Trace messages about the assemblies added the
the "parts" catalog, all probe assemblies found, and total discovery time are written to the
debug log and can help diagnose a problem.
The easiest and most common way to alter the default discovery behavior is to change the
search and/or ignore pattern(s) DevForce will use.
For ASP.NET and Silverlight applications the default SearchPattern is "*.dll"; for other
applications the default is "*.dll" and "*.exe".
For all application types, the default IgnorePatterns are set to exclude IdeaBlade and system
assemblies, as well as assemblies from many third party control suites.
Both SearchPatterns and IgnorePatterns accept either simple wildcards or Regex
patterns. Simple wildcard searches are converted into Regex patterns by DevForce when
probing occurs. The search is case insensitive.
When should you use SearchPatterns versus IgnorePatterns? SearchPatterns are useful
when you know specifically what you're looking for; while IgnorePatterns are helpful when
you know what you don't want.
Here's a sample using the SearchPatterns to limit probing to only a single
assembly. Generally in larger applications you'll have multiple assemblies to be probed, so
you should be sure to include one or more patterns to cover them. This first clears the default
SearchPatterns, and then sets a pattern for a specific assembly named "MyDomainModel.dll".
C#
IdeaBlade.Core.Composition.CompositionHost.SearchPatterns.Clear();
IdeaBlade.Core.Composition.CompositionHost.SearchPatterns.Add("MyDomainModel.dll");
VB
IdeaBlade.Core.Composition.CompositionHost.SearchPatterns.Clear()
IdeaBlade.Core.Composition.CompositionHost.SearchPatterns.Add("MyDomainModel.dll")
Now let's try modifying the IgnorePatterns. DevForce will by default ignore the
following: "IdeaBlade.*", "System.*", "Microsoft.*", "*.vshost.*", "mscorlib.*",
"WindowsBase.*", "PresentationCore.*", "PresentationFramework.*", "Intersoft.*",
"Telerik.*", "DevExpress.*", "Infragistics*", "WPFToolkit.*", "Syncfusion.*", "Janus.*",
"C1.*", and "PerpetuumSoft.*".
You shouldn't clear this list, and you certainly shouldn't remove the "IdeaBlade.*" assemblies,
since both actions will cause your application to fail, but you can add additional third party
tools and suites to the list. For example, here we're adding an exclusion for all assemblies
(and other files) matching "GalaSoft.*".
C# IdeaBlade.Core.Composition.CompositionHost.IgnorePatterns.Add("GalaSoft.*");
VB IdeaBlade.Core.Composition.CompositionHost.IgnorePatterns.Add("GalaSoft.*")
You need to set the SearchPatterns and IgnorePatterns as early as possible in your
application, since as soon as you use the IdeaBladeConfig.Instance, TraceFns and DebugFns
methods, or an EntityManager, initialization will automatically occur.
In an EntityServer hosted by IIS or an ASP.NET application, the best place to set the patterns
is in the application startup logic in the global.asax.
In Silverlight, you should do this in the Application_Startup logic to ensure that your changes
are made before probing occurs.
In a desktop application, set the patterns before you begin using an EntityManager or other
DevForce components.
If you've set SearchPatterns and/or IgnorePatterns, it's usually a good idea to check the
debug log for the tracing messages written about what DevForce has discovered. It's easy to
mistype a pattern and not have your assemblies probed, or alternately to have too many
assemblies probed resulting in poor startup performance.
The first time DevForce finds and uses your custom classes it will log this fact to the debug
log (or other ITraceLogger implementation). This information, along with logging about all
assemblies loaded into the "parts" catalog, can help in diagnosing problems should they occur.
What should be discovered
There are several components of your application which DevForce must find in order for your
application to work as wanted.
All custom implementations of DevForce interfaces and base types. These are the exports
placed in the parts catalog.
Entity models (aka domain models) - DevForce must be able to find any assembly holding a
model. It uses this assembly to load model metadata and gather other information about the
types in your model.
Remote server methods - If your application is using either remote server methods or "Push"
methods, then DevForce must be able to find them.
POCO providers and types - For DevForce to find your POCO types and providers, they must
be defined in an assembly probed.
Known types - For any of the types which can be transmitted across tiers - for example those
types passed to or from a remote server method - DevForce must know these types before
initiating communications.
In all the above cases, DevForce will look through all the assemblies which have been probed
to find what it needs. If you've chosen to modify either the SearchPatterns or IgnorePatterns,
make sure that the patterns will allow all assemblies needed to be discovered. You can check
the read only CompositionHost.Instance.ProbeAssemblies at runtime to see which assemblies
were found; they're also listed in the debug log.
On-demand discovery
Large Silverlight applications can be broken into smaller modules, downloaded "on demand".
Visual Studio tooling allows the developer to create separate deployment packages which can
be dynamically downloaded as needed. To use DevForce within a downloaded module you
must register it for on-demand discovery.
This feature is available only in Silverlight.


Overview
On-demand discovery allows DevForce to probe your new content for any entity models,
known types, or custom implementations of DevForce types.
You can ask DevForce to download the content, or once downloaded you can tell DevForce
about it. Adding dynamic content for on-demand discovery causes DevForce to recompose its
"parts" catalog and metadata about your models and components. If you have dynamic
content which you neglect to tell DevForce about, you'll find both that your customizations
are not found and exceptions occur when using the entity model. (The most likely error is a
message that the entity type queried is not a "known type".)
You can register new modules at any time, and start using your entity model and other
DevForce features within it as soon as discovery completes. The CompositionHost will fire a
Recomposed event once ready, which you can listen on to check for completion or if any
errors occurred.
To perform on-demand discovery, use one of the Add overloads. Trace messages are also
generated, which you can capture using a custom logger or trace viewer.
It's common practice to use Application Library Caching (ALC) for XAPs in a multi-module
application. The DevForce assemblies all support ALC.
With Prism modularity
If you're using Prism modularity you can tell DevForce about the new content, either once the
module downloads or when it initializes. Here's a sample which adds the Uri of the
downloaded module to the CompositionHost.
C#
public void Download(string moduleName) {
this.ModuleManager.LoadModuleCompleted += this.ModuleManager_LoadModuleCompleted;
this.ModuleManager.LoadModule(moduleName);
}
private void ModuleManager_LoadModuleCompleted(object sender,
LoadModuleCompletedEventArgs e) {
var uri = new Uri(e.ModuleInfo.Ref, UriKind.Relative);
IdeaBlade.Core.Composition.CompositionHost.Add(uri);
}
VB
Public Sub Download(ByVal moduleName As String)
AddHandler Me.ModuleManager.LoadModuleCompleted, _
AddressOf ModuleManager_LoadModuleCompleted
Me.ModuleManager.LoadModule(moduleName)
End Sub
Private Sub ModuleManager_LoadModuleCompleted(ByVal sender As Object, _
ByVal e As LoadModuleCompletedEventArgs)
Dim uri = New Uri(e.ModuleInfo.Ref, UriKind.Relative)
IdeaBlade.Core.Composition.CompositionHost.Add(uri)
End Sub
See our sample DevForce/Prism Modularity Quickstart for more information.
With MEF deployment catalog
If you're using the MEF DeploymentCatalog, once the catalog downloads you can tell
DevForce that new content is available by adding the DeploymentCatalog to the
CompositionHost. For example:
C#
public void AddXap(string uri) {
DeploymentCatalog catalog;
catalog = new DeploymentCatalog(uri);
catalog.DownloadAsync();
catalog.DownloadCompleted += new
EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(catalog_DownloadComplet
ed)
}

private void catalog_DownloadCompleted(object sender,
System.ComponentModel.AsyncCompletedEventArgs e) {
IdeaBlade.Core.Composition.CompositionHost.Add(sender as DeploymentCatalog);
}
V
B
Public Sub AddXap(ByVal uri As String)
Dim catalog As DeploymentCatalog
catalog = New DeploymentCatalog(uri)
catalog.DownloadAsync()
AddHandler catalog.DownloadCompleted, AddressOf catalog_DownloadCompleted
End Sub

Private Sub catalog_DownloadCompleted(ByVal sender As Object, _
ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
IdeaBlade.Core.Composition.CompositionHost.Add(TryCast(sender, _
DeploymentCatalog))
End Sub
If using the DeploymentCatalogService shown in MEF samples, you likely already have code
for the catalog_DownloadCompleted event handler. Add the line to call
CompositionHost.Add for the catalog.
With a DynamicXap
If you're not using MEF or Prism there's still another means of notifying DevForce about
dynamic content with the DynamicXap class. The class can be constructed in a few different
ways, but the easiest may be with a Uri, to have DevForce automatically download the
content.
C#
public void DoDownload(string xapName) {
var xap = new IdeaBlade.Core.DynamicXap(new Uri(xapName, UriKind.Relative));
IdeaBlade.Core.Composition.CompositionHost.Add(xap);
}
VB
Public Sub DoDownload(ByVal xapName As String)
Dim xap = New IdeaBlade.Core.DynamicXap(New Uri(xapName, UriKind.Relative))
IdeaBlade.Core.Composition.CompositionHost.Add(xap)
End Sub
Listening for DynamicXap load
You can load a DynamicXap independently of adding it to the CompositionHost. Listen on its
Loaded event to tell you when the download has completed or if an error occurred.
C#
var xap = new DynamicXap(new Uri("SecondModule.xap", UriKind.Relative));
xap.Loaded += (o, args) => {
if (args.HasError) {
TraceFns.WriteLine(args.Error.Message);
} else {
var dzap = o as DynamicXap;
TraceFns.WriteLine(dzap.Name + " downloaded");
}
};
VB
Dim xap = New DynamicXap(New Uri("SecondModule.xap", UriKind.Relative))
AddHandler xap.Loaded, Sub(o, args)
If args.HasError Then
TraceFns.WriteLine(args.Error.Message)
Else
Dim dzap = TryCast(o, DynamicXap)
TraceFns.WriteLine(dzap.Name & " downloaded")
End If
End Sub
Listening for recomposition events
Regardless of how you've added content to the CompositionHost, you can listen for its
Recomposed event to notify you when new content has been downloaded.
C# CompositionHost.Recomposed += CompositionHost_Recomposed;
VB AddHandler CompositionHost.Recomposed, AddressOf CompositionHost_Recomposed
The RecomposedEventArgs will indicate the Xap or assembly triggering the recomposition, or
the error if an exception was thrown. You can use the Name property on the Xap to identify
the on-demand module.
Discovery by context
You can gain finer-grained control over the discovery process by using type and metadata
filters with a composition context.


The CompositionContext
You may have noticed a CompositionContext argument can be passed into the EntityManager
constructor, and the probe messages in your log all mention it too:

Just what is this, and why does it keep showing up everywhere? In the discovery topic we
discussed how DevForce uses MEF to discover the extensible components of your
application, but what we didn't mention is that this discovery is contextual. The default
context is just that, a default, and always used when you haven't specified a context. The
CompositionContext.Default provides no special type or metadata filtering.
When and why to use a CompositionContext?
The CompositionContext is used in DevForce's built-in support for faking, but it's also useful
for creating mocks during testing, and in any situation in which you might want several
different custom implementations of an interface or base class. For example, you might have a
requirement that in most cases you'll use an EntityServerQueryInterceptor in a certain way,
but in particular situations you'd like different interceptor logic. With a custom
CompositionContext you can easily define that "particular situation", and define a custom
EntityServerQueryInterceptor to be used only for it.
Most, but not all, of the DevForce extensible components support a custom context. Those
that do not are ones needed during application initialization and not as part of EntityManager
activities. For example, custom loggers and components controlling service or proxy
configuration cannot be discovered or composed contextually.
You can define and use any number of CompositionContexts within your application. As
we'll see below it's generally the EntityManager, via its constructor, which determines the
context in use.
Creating a custom CompositionContext
You can implement the ICompositionContextResolver interface or extend the
BaseCompositionContextResolver to define and resolve your custom
CompositionContexts. The BaseCompositionContextResolver will automatically register any
statically defined composition contexts found within the sub-class, but you can also override
its GetCompositionContext method to programmatically define new contexts.
Here's a sample resolver defining two custom contexts, "MockQuery" and "Admin":
C#
public class MyCompositionContextResolver : BaseCompositionContextResolver {

public static CompositionContext MockQuery = CompositionContext.Fake
.WithGenerator(typeof(MockEntityServerQueryInterceptor))
.WithName("MockQuery");

public static CompositionContext Admin = CompositionContext.Default
.WithGenerator(typeof(AdminEntityServerSaveInterceptor))
.WithGenerator(typeof(AdminEntityServerQueryInterceptor))
.WithName("Admin");
}
VB
Public Class MyCompositionContextResolver
Inherits BaseCompositionContextResolver

Public Shared MockQuery As CompositionContext = _
CompositionContext.Fake. _
WithGenerator(GetType(MockEntityServerQueryInterceptor)). _
WithName("MockQuery")

Public Shared Admin As CompositionContext = _
CompositionContext.Default. _
WithGenerator(GetType(AdminEntityServerSaveInterceptor)). _
WithGenerator(GetType(AdminEntityServerQueryInterceptor)). _
WithName("Admin")
End Class
We also see above that these custom contexts are defined from existing built-in
contexts. Once created a CompositionContext is immutable, but you can easily create new
contexts based on an existing context and supply different composition criteria. Above we
see a new context based on the Fake context but using its own custom
EntityServerQueryInterceptor, and another context based on the Default context but using
custom query and save interceptors. The sample above is also defining the extensible types
specific to the context (although we didn't show the code for them).
In defining a custom composition context you must both register the context and define the
extensible components it will use. There are two mechanisms used to accomplish this: one
allows you to specify the types to be used when you create the context, while the other allows
you to define metadata filters to be applied during discovery.
Discovery with types specified
This approach is the one you'll see most often in discovery examples, and was also used in the
sample above. Here you specify the generators or the types to be used by the custom
context. Remember to do two things:
1. Use the WithGenerator method to register types to the context.
2. Mark these types with the System.ComponentModel.Composition.PartNotDiscoverable
attribute. This is required to hide the types from standard MEF discovery, since here
DevForce is preempting that discovery.
Here's a sample resolver defining the composition contexts. Instead of defining static fields
we're overriding the GetCompositionContext method to define the contexts at run time.
C#
public class ContextResolver : BaseCompositionContextResolver {

public override CompositionContext GetCompositionContext(string compositionContextName) {

if (compositionContextName == "Test") {
return CompositionContext.Default
.WithGenerator(new Type[] { typeof(TestLoginManager), typeof(TestQueryInterceptor) })
.WithName("Test");
} else if (compositionContextName == "Dev") {
return CompositionContext.Default
.WithGenerator(new Type[] { typeof(DevLoginManager) })
.WithName("Dev");
} else return base.GetCompositionContext(compositionContextName);
}
}
VB
Public Class ContextResolver
Inherits BaseCompositionContextResolver

Public Overrides Function GetCompositionContext(ByVal compositionContextName As String) As
CompositionContext

If compositionContextName = "Test" Then
Return CompositionContext.Default.WithGenerator(New Type() {GetType(TestLoginManager),
GetType(TestQueryInterceptor)}).WithName("Test")
ElseIf (compositionContextName = "Dev") Then
Return CompositionContext.Default.WithGenerator(New Type() {
GetType(DevLoginManager)}).WithName("Dev"); }
Else
Return MyBase.GetCompositionContext(compositionContextName)
End If
End Function
End Class
Remember that your resolver may need to be defined on both client and server, depending on
the type generators it defines and where they will be used. For example, an
IEntityLoginManager is used only on the server.
Be sure to decorate the types used by your custom contexts with the MEF
PartNotDiscoverable attribute. This tells both MEF and DevForce to ignore the types during
standard discovery.
Below are a few very simple samples of custom types for the contexts defined above.
C#
[PartNotDiscoverable]
public class DevLoginManager : IEntityLoginManager {

public IPrincipal Login(ILoginCredential credential, EntityManager entityManager) {
return new UserBase(new UserIdentity("Dev", "Custom", true), new string[] { "Dev" });
}

public void Logout(IPrincipal principal, EntityManager entityManager) {
}
}

[PartNotDiscoverable]
public class TestLoginManager : IEntityLoginManager {

public IPrincipal Login(ILoginCredential credential, EntityManager entityManager) {
return new UserBase(new UserIdentity("Test", "Custom", true), new string[] { "Test" });
}

public void Logout(IPrincipal principal, EntityManager entityManager) {
}
}

[PartNotDiscoverable]
public class TestQueryInterceptor : EntityServerQueryInterceptor {
protected override bool ExecuteQuery() {
TraceFns.WriteLine("User " + this.Principal.Identity.Name + " is executing query " +
this.Query.ToString());
return base.ExecuteQuery();
}
}
VB
<PartNotDiscoverable>
Public Class DevLoginManager
Implements IEntityLoginManager

Public Function Login(ByVal credential As ILoginCredential, ByVal entityManager As
EntityManager) As IPrincipal
Return New UserBase(New UserIdentity("Dev", "Custom", True), New String() { "Dev" })
End Function

Public Sub Logout(ByVal principal As IPrincipal, ByVal entityManager As EntityManager)
End Sub
End Class

<PartNotDiscoverable>
Public Class TestLoginManager
Implements IEntityLoginManager

Public Function Login(ByVal credential As ILoginCredential, ByVal entityManager As
EntityManager) As IPrincipal
Return New UserBase(New UserIdentity("Test", "Custom", True), New String() { "Test" })
End Function

Public Sub Logout(ByVal principal As IPrincipal, ByVal entityManager As EntityManager)
End Sub
End Class

<PartNotDiscoverable>
Public Class TestQueryInterceptor
Inherits EntityServerQueryInterceptor
Protected Overrides Function ExecuteQuery() As Boolean
TraceFns.WriteLine("User " & Me.Principal.Identity.Name & " is executing query " &
Me.Query.ToString())
Return MyBase.ExecuteQuery()
End Function
End Class
Discovery with metadata filters
Instead of defining the types to be used with the custom context when you create the context
you can instead define metadata filtering rules. Here you'll do the following:
1. Build one or more metadata filters with BuildExportFilter.
2. Registers the filters with the context using WithFilter and WithTypeFilter methods.
3. Mark your types with the System.ComponentModel.Composition.ExportMetadata and
System.ComponentModel.Composition.InheritedExport attributes.
Here's a sample resolver defining the composition contexts. As above we overrode the
GetCompositionContext method to define the contexts at run time. The BuildExportFilter
method is used to build a filter for the metadata attributes to be used. Here we'll be using only
a single metadata attribute named "Env". We're also using the WithFilter method to indicate
that any types meeting the metadata criteria will be used. We could also use the
WithTypeFilter to indicate specific metadata by type.
C#
public class ContextResolver : BaseCompositionContextResolver {

public override CompositionContext GetCompositionContext(string compositionContextName) {

if (compositionContextName == "Test") {
var filter = CompositionContext.BuildExportFilter("Env", "Test");
return CompositionContext.Default
.WithFilter(filter)
.WithName("Test");
} else if (compositionContextName == "Dev") {
var filter = CompositionContext.BuildExportFilter("Env", "Dev");
return CompositionContext.Default
.WithFilter(filter)
.WithName("Dev");
} else return base.GetCompositionContext(compositionContextName);
}
}
VB
Public Class ContextResolver
Inherits BaseCompositionContextResolver

Public Overrides Function GetCompositionContext(ByVal compositionContextName As String) As
CompositionContext

If compositionContextName = "Test" Then
Dim filter = CompositionContext.BuildExportFilter("Env", "Test")
Return CompositionContext.Default.WithFilter(filter).WithName("Test")
ElseIf compositionContextName = "Dev" Then
Dim filter = CompositionContext.BuildExportFilter("Env", "Dev")
Return CompositionContext.Default.WithFilter(filter).WithName("Dev")
Else
Return MyBase.GetCompositionContext(compositionContextName)
End If
End Function
End Class
We must decorate our types to add the metadata wanted. This requires both the
ExportMetadata attribute, to add metadata to the type, and the InheritedExport attribute,
which is required by MEF to ensure that the custom metadata is found.
Here are the same simple classes as defined above, but this time using metadata.
C#
[InheritedExport(typeof(IEntityLoginManager))]
[ExportMetadata("Env", "Dev")]
public class DevLoginManager : IEntityLoginManager {

public IPrincipal Login(ILoginCredential credential, EntityManager entityManager) {
return new UserBase(new UserIdentity("Dev", "Custom", true), new string[] { "Dev" });
}

public void Logout(IPrincipal principal, EntityManager entityManager) {
}
}

[InheritedExport(typeof(IEntityLoginManager))]
[ExportMetadata("Env", "Test")]
public class TestLoginManager : IEntityLoginManager {

public IPrincipal Login(ILoginCredential credential, EntityManager entityManager) {
return new UserBase(new UserIdentity("Test", "Custom", true), new string[] { "Test" });
}

public void Logout(IPrincipal principal, EntityManager entityManager) {
}
}

[InheritedExport(typeof(EntityServerQueryInterceptor))]
[ExportMetadata("Env", "Test")]
public class TestQueryInterceptor : EntityServerQueryInterceptor {

protected override bool ExecuteQuery() {
TraceFns.WriteLine("User " + this.Principal.Identity.Name + " is executing query " +
this.Query.ToString());
return base.ExecuteQuery();
}
}
VB
<InheritedExport(GetType(IEntityLoginManager)), ExportMetadata("Env", "Dev")>
Public Class DevLoginManager
Implements IEntityLoginManager

Public Function Login(ByVal credential As ILoginCredential, ByVal entityManager As
EntityManager) As IPrincipal
Return New UserBase(New UserIdentity("Dev", "Custom", True), New String() { "Dev" })
End Function

Public Sub Logout(ByVal principal As IPrincipal, ByVal entityManager As EntityManager)
End Sub
End Class

<InheritedExport(GetType(IEntityLoginManager)), ExportMetadata("Env", "Test")>
Public Class TestLoginManager
Implements IEntityLoginManager

Public Function Login(ByVal credential As ILoginCredential, _
ByVal entityManager As EntityManager) As IPrincipal
Return New UserBase(New UserIdentity("Test", "Custom", True), New String() { "Test" })
End Function

Public Sub Logout(ByVal principal As IPrincipal, ByVal entityManager As EntityManager)
End Sub
End Class

<InheritedExport(GetType(EntityServerQueryInterceptor)), ExportMetadata("Env", "Test")>
Public Class TestQueryInterceptor
Inherits EntityServerQueryInterceptor

Protected Overrides Function ExecuteQuery() As Boolean
TraceFns.WriteLine("User " & Me.Principal.Identity.Name & " is executing query " & _
Me.Query.ToString())
Return MyBase.ExecuteQuery()
End Function
End Class
Using a CompositionContext
The CompositionContext is usually specified by name during the construction of an
EntityManager:
C#
var em = new EntityManager(compositionContextName:
MyCompositionContextResolver.MockQuery.Name);
VB
Dim em As New
EntityManager(compositionContextName:=MyCompositionContextResolver.MockQuery.Name)
We saw earlier that every custom CompositionContext was also given a unique name, via the
WithName method. It's this name which is provided in the EntityManager constructor. The
name defines the context to be used for all composition performed during the login, query,
save, and other operations performed by the EntityManager, and the EntityServer it's
connected to. In a few types, such as the VerifierEngine, the CompositionContext may also
be set explicitly. This is because these classes may be instantiated and used independently of
any EntityManager.
If the CompositionContext name isn't provided to an EntityManager the
CompositionContext.Default will be used.
Custom fakes and mocks
Custom composition contexts are particularly useful in creating custom fakes and mocks for
testing. The built-in support for faking is discussed separately in more detail, but here we
show how to create custom contexts to aid in testing.
Let's assume we want to test how well our client code copes with a query exception thrown on
the server. You generally don't want to force a query exception by modifying your production
code, but you can test this easily with a mock.
C#
public class TestCompositionContextResolver : BaseCompositionContextResolver {
///<summary>
/// A version of the DevForce FakeCompositionContext
/// extended by a custom EntityServerQueryInterceptor
///</summary>
public static CompositionContext FailingQueryContext = CompositionContext.Fake
.WithGenerator(typeof(FailingEntityServerQueryInterceptor));
}

///<summary>
/// An EntityServerQueryInterceptor that throws an
/// exception no matter what the query.
///</summary>
[PartNotDiscoverable]
public class FailingEntityServerQueryInterceptor : EntityServerQueryInterceptor {
protected override bool ExecuteQuery() {
throw new InvalidOperationException();
}
}
VB
Public Class TestCompositionContextResolver
Inherits BaseCompositionContextResolver
'''<summary>
''' A version of the DevForce FakeCompositionContext
''' extended by a custom EntityServerQueryInterceptor
'''</summary>
Public Shared FailingQueryContext As CompositionContext = _
CompositionContext.Fake.WithGenerator(GetType(FailingEntityServerQueryInterceptor))
End Class

'''<summary>
''' An EntityServerQueryInterceptor that throws an
''' exception no matter what the query
'''</summary>
<PartNotDiscoverable()> _
Public Class FailingEntityServerQueryInterceptor
Inherits EntityServerQueryInterceptor
Protected Overrides Function ExecuteQuery() As Boolean
Throw New InvalidOperationException()
End Function
End Class
Here we've written a FailingEntityServerQueryInterceptor that always throws an exception no
matter what the query. Note the PartNotDiscoverable attribute on the custom class. This tells
MEF to skip this class when discovering EntityServerQueryInterceptors. We don't want this
one popping up in our production application!
Now that we've created a custom context that incorporates our interceptor, let's see how it
affects a client-side query.
C#
[TestMethod]
public void MockQueryFail() {

var em = new DomainModelEntityManager(compositionContextName:
TestCompositionContextResolver.FailingQueryContext.Name);

var query = em.Customers.Where(c => c.CompanyName.StartsWith("S"));
query.ToList();
// Yep, this fails, better think about some try/catch logic.
}
VB
<TestMethod> _
Public Sub MockQueryFail()

Dim em As New DomainModelEntityManager(compositionContextName :=
TestCompositionContextResolver.FailingQueryContext.Name)

Dim query = em.Customers.Where(Function(c) c.CompanyName.StartsWith("S"))
query.ToList()
' Yep, this fails, better think about some try/catch logic.
End Sub

Faking
Last modified on April 28, 2011 15:47
Contents
Faking with CompositionContext.Fake
Simple Faking
Working directly with a fake backing store
o Local vs. remote stores
o Store methods
Troubleshooting
Additional resources
We've seen how DevForce supports discovery by context, something particularly useful in
testing. DevForce also contains built-in support for faking using this facility.
There are a few definitions of faking, but let's use one from Martin Fowler in his post "Mocks
Aren't Stubs": "Fakeobjects actually have working implementations, but usually take some
shortcut which makes them not suitable for production (an in memory database is a good
example)."


Faking with CompositionContext.Fake
CompositionContext.Fake is a composition context in which "fake" implementations of
several important DevForce interfaces are provided to simulate end-to-end query and save
operations against a real backing store. Faking is also useful in facilitating model-first
development, and providing data and functionality for demo applications.
CompositionContext.Fake components include:
1. Id generation with the FakeIdGenerator to allow both temporary ids for new entities and
translation to "real" ids when a save is performed.
2. An in-memory data store with the EntityServerFakeBackingStore.
3. Query functionality with the EdmQueryExecutorFake.
4. Save functionality with the EdmSaveExecutorFake.
These are not stubs. They are rich implementation that provide functionality almost identical
to that of their "real" counterparts. Faked queries and saves return virtually the same results
you would expect from a real data store, but instead use a fake data store, called the
EntityServerFakeBackingStore. Once you populate this store, you can issue standard queries
and saves from an EntityManager created for the context without any additional code.
Note that other DevForce extensions, such as IEntityLoginManager, are not faked, so either
DevForce defaults or your custom implementations will be used for those.
You can create multiple named fake contexts, and custom contexts based on the standard
CompositionContext.Fake. Each unique context uses its own backing store. With a custom
fake context you can supply additional fake functionality of your own.
Simple Faking
At the simplest, all you need to do is create an EntityManager for the default fake context and
issue queries and saves against it. Of course, unless you've pre-populated the fake backing
store queries will return no data until you've first saved some entities.
Here we create a new EntityManager and populate the backing store with a few test entities:
C#
var em = new DomainModelEntityManager(compositionContextName:
CompositionContext.Fake.Name);
PopulateBackingStore(em);
VB
Dim em As New DomainModelEntityManager(compositionContextName:=
CompositionContext.Fake.Name)
PopulateBackingStore(em)
C#
private void PopulateFakeBackingStore(EntityManager em) {
var customer = new Customer { CompanyName = "Test Company" };
em.AddEntity(customer);

var employee = new Employee { FirstName= "Fred", LastName = "Smith"};
em.AddEntity(employee);

for (int i = 0; i < 5; i++) {
var salesOrder = new OrderSummary { Employee=employee, Customer = customer};
em.AddEntity(salesOrder);
}
em.SaveChanges();
}
VB
Private Sub PopulateFakeBackingStore(ByVal em As EntityManager)
Dim customer = New Customer() With {.CompanyName = "Test Company"}
em.AddEntity(customer)

Dim employee = New Employee() With {.FirstName = "Fred", .LastName = "Smith"}
em.AddEntity(employee)

For i As Integer = 0 To 4
Dim salesOrder = New OrderSummary() With {.Employee = employee, .Customer = customer}
em.AddEntity(salesOrder)
Next
em.SaveChanges()
End Sub
Once the backing store is populated with test data we can then use the EntityManager as
usual. Here we clear it first, to ensure that the EntityManager is querying from the backing
store.
C#
em.Clear(); // clear cache; no memory of prior entities

var query = em.Customers.Include(c => c.OrderSummaries)
.Where(c => c.OrderSummaries.Any(os => os.Employee.FirstName == "Fred"));
VB
em.Clear() ' clear cache; no memory of prior entities

Dim query As em.Customers.Include(Function(c) c.OrderSummaries).Where _
(Function(c) c.OrderSummaries.Any(Function(os) os.Employee.FirstName = "Fred"))
Working directly with a fake backing store
You can access a fake backing store via a fake CompositionContext, for example:
C# var store EntityManager.CompositionContext.GetFakeBackingStore();
VB Dim store = EntityManager.CompositionContext.GetFakeBackingStore()
Local vs. remote stores
Different backing stores are used in 2-tier vs. n-tier applications,
EntityServerFakeBackingStore.Local and EntityServerFakeBackingStore.Remote. The Local
store, which is not available in Silverlight applications, allows you to perform synchronous
queries and saves when not using a remote EntityServer. The Remote store is used with
Silverlight applications and any others using a remote EntityServer. Generally, you won't be
concerned whether the store in use is local or remote unless you're working directly with it,
for example to clear or populate it.
Store methods
The entities stored and retrieved by the EntityServerFakeBackingStore are actually held in an
EntityCacheState. The EntityServerFakeBackingStore provides methods to allow you to work
directly with both it and the underlying EntityCacheState. You can use Save or SaveAsync to
save the store to a file or stream, and Restore or RestoreAsync to restore data into the
store. Clear or ClearAsync can be used to clear the store (for example to clear the store
between tests).
Note that only the asynchronous versions of these methods are available in Silverlight
applications.
The EntityCacheState makes it easy to load test data into the backing store, possibly from a
test database. The EntityCacheState can be initially loaded from an EntityManager, and
allows you to save to and restore from a file or stream. Using these techniques you can write a
small helper method or application, a "TestDataMother" if you will, which is responsible for
creating and loading test data.
Troubleshooting
If you deploy an application using faking to IIS, you must also modify a web server setting to
allow services using the fake composition context name to start successfully. Set
allowDoubleEscaping to true:
XML
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="true"/>
</security>
</system.webServer>
Additional resources
The BookShelf sample application contains an example of a "TestDataMother".
The known type primer
Last modified on April 28, 2011 16:00
Contents
What is a known type?
When should I care?
What does DevForce provide automatically?
How to indicate a known type?
Troubleshooting
You've landed here because you're trying to use some simple feature of DevForce - say a
remote server method or POCO type - and you've gotten a strange error message about
"known types". Here we'll try to dispel some of the misconceptions and explain a few of the
mysteries of why known types are so important in your DevForce application.


What is a known type?
In an n-tier application, such as a DevForce Silverlight application or any application using a
remote EntityServer, data must be moved between tiers: it must be serialized for transmission
and deserialized by the recipient. In DevForce, this serialization and deserialization is done
using the .NET DataContractSerializer (DCS). The serializer must be able to transmit queries,
entities, POCOs, RSM arguments and return values - anything you send to or receive from the
server.
The DCS uses contracts to tell it how to process the data it receives; whenever the contract is
imprecise, for example when a property is typed as Object, or as an interface or abstract type,
the DCS needs to be told what types are known to be in the object graph, hence known types.
In DevForce it's not only properties which might be vague, but method arguments and return
values too may not be strongly typed by the underlying DevForce contracts, and must instead
be made known at run time.
It should be obvious that a known type must also be serializable. A type is generally
serializable if it has a parameterless public constructor, or it's marked up with DataContract
and DataMember attributes. Here's more information from Microsoft on what can be
serialized with the DCS.
When should I care?
Login - You may have noticed two things about the Login method: it takes an
ILoginCredential, and from that credential produces an IPrincipal. Two interfaces, whose
concrete implementations must be known at run time. Therefore, any custom
ILoginCredential or IPrincipal (or IIdentity) must be made known to DevForce as a known
type. Fortunately, DevForce will specifically look for custom implementations of these
interfaces and add them to a list of known types it builds for the serializer so you do not have
to do anything special, but it's still worth remembering that these are known types.
Remote Server Methods - If you've created any remote server methods (sometimes called
either RSM or RPC), you've also likely passed data both as arguments to the methods and as
return values. Remember the signature for the RSM:
C#
public delegate Object ServerMethodDelegate(IPrincipal principal, EntityManager
serverEntityManager, params Object[] args);
VB
Public Delegate Function ServerMethodDelegate(ByVal principal As IPrincipal, _
ByVal serverEntityManager As EntityManager, ByVal ParamArray args() As Object) As Object
A method which takes zero or more user-specified objects, and returns an object (which might
be a list or graph of objects). Since the signature is not strongly typed, everything passed into
or out of the method must be designated as a known type. In this case, DevForce won't do this
discovery for you - you must tell DevForce, or the serializer, the known types involved.
Push (Notification Service) - As with remote server methods, the types which can be sent and
received are not known until run time. When registering for the service you can pass zero or
more objects; the notification data returned by the service is also an object array. Since the
signatures are not strongly typed, the concrete types used must all be designated as known
types.
POCO - POCO types which will be passed between tiers must also be identified as known
types. If your POCO type has a Key attribute DevForce will automatically add your POCO
type as a known type, but it's good to remember that POCO types must be known types.
Projection into type - When you project query results into a custom type, that custom type
must be designated as a known type.
Query Contains clause - In LINQ a Contains clause is used in place of the SQL IN
operator. The list on which the Contains is defined must be a known type if the query will be
sent to the server. DevForce automatically defines a known type for all List<T> where T is a
numeric type, a string, a DateTime or a GUID. If your list contains some other type the list
for this type must be designated as a known type.
Note that primitive types are already known to the DCS and if you are using these, for
example as arguments to or a return value from an RSM, you do not need to designate the
type as a known type. Here's a list from Microsoft on the primitives it automatically
recognizes.
What does DevForce provide automatically?
At start up, and upon recomposition when an on-demand XAP is downloaded, DevForce will
automatically build a list of known types to be provided to the serializer. This list is actually
provided to any DCS which might be used: the serializer used to transmit data between tiers,
a serializer used when creating or restoring an EntityCacheState, and serializers used for
specialized cloning.
This list contains:
All entity and complex types found in any entity models, and List<T> and RelatedEntityList<T>
for each.
List<T> where T is a numeric, string, DateTime or GUID.
All DevForce types expected to be transmitted between tiers.
DateTimeOffset and StringComparison.
Any discovered ILoginCredential, IDataSourceKeyResolver, IIdGenerator, IPrincipal, and
IIdentity implementations.
Types discovered via IKnownType, DiscoverableTypeMode.KnownType and
IKnownTypeProvider.
You may notice that any types marked with the .NET KnownType attribute are not included
in this list. The serializer has two ways of obtaining known types: one is the list provided to
it upon construction, and second is via the KnownType attributes it finds within the object
graph being serialized/deserialized. The list DevForce builds is the list passed to the serializer
constructor; but your object graph can include KnownType attributes to directly tell the
serializer what to expect within the object graph. Note that the KnownType attribute is not
used to indicate that the type itself is a known type, but instead to indicate other types are
known types. This is a subtle but important distinction: you can tell DevForce about known
types (via DevForce interfaces) and DevForce will in turn tell the serializer; or you can
directly tell the serializer (via the .NET KnownType attribute). The end result is the same: the
serializer will use the known type information whenever the contract definition is imprecise.
How to indicate a known type?
Have the type implement the I deaBlade.EntityModel.I KnownTypemarker interface
When you have control over the type (i.e., it's not a .NET type or one defined in a third-party
assembly), using the marker interface is often the simplest implementation.
C#
public class OrderRequestInfo : IKnownType {
public int Top { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
VB
Public Class OrderRequestInfo _
Implements IKnownType
Public Property Top() As Integer
Public Property StartDate() As Date
Public Property EndDate() As Date
End Class
Decorate the type with the I deaBlade.EntityModel.DiscoverableTypeattribute
This attribute is functionally equivalent to the IKnownType marker interface.
C#
[DiscoverableType(DiscoverableTypeMode.KnownType)]
public class OrderRequestInfo {
public int Top { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
VB
<DiscoverableType(DiscoverableTypeMode.KnownType)> _
Public Class OrderRequestInfo
Public Property Top() As Integer
Public Property StartDate() As Date
Public Property EndDate() As Date
End Class
Return the type from an I deaBlade.EntityModel.I KnownTypeProvider
The IKnownTypeProvider allows you to specify any type - your own, .NET or third party
types - so is useful either when you don't want to modify type declarations or cannot. Any
number of IKnownTypeProviders may be defined.
C#
public class KnownTypeProvider : IKnownTypeProvider {

public IEnumerable<Type> AddKnownTypes() {

var list = new Type[] { typeof(OrderRequestInfo),
typeof(OrderResponseInfo),
typeof(List<DateTimeOffset>)
};

return list;
}
}
VB
Public Class KnownTypeProvider
Implements IKnownTypeProvider

Public Function AddKnownTypes() As IEnumerable(Of Type)

Dim list = New Type() {GetType(OrderRequestInfo), _
GetType(OrderResponseInfo), GetType(List(Of DateTimeOffset))}

Return list
End Function
End Class
Add the System.Runtime.SerializationKnownTypeAttribute to another type (such as an
entity)
Here you're marking up your object graph to indicate to the serializer what other types to
expect. DevForce is unaware of types marked with the KnownType attribute, so this cannot
be used when defining POCO types.
C#
[KnownType(typeof(OrderRequestInfo))]
public partial class OrderSummary { ... }
VB
<KnownType(GetType(OrderRequestInfo))> _
Partial Public Class OrderSummary
...
End Class
Troubleshooting
So you've received the dreaded formatter exception, something like "The formatter threw an
exception while trying to deserialize the message ..." and it goes on for 3 or 4
lines. Somewhere in there it mentions a type (or contract name) and says to add the type to
the list of known types. What? How? Didn't I already do that?
This message is coming straight from the serializer, and does tell you exactly what it found to
be wrong, albeit in somewhat confusing language.
1. Make sure that the type is defined on both client and server. This is easy to overlook, but
should be intuitively obvious. Both the client and server should be aware of any types to be
passed between them. With Silverlight applications, DevForce ensures this of entities in the
model by including a link to the generated code in the Silverlight application. You can do the
same with your own types: define the type in a file in a Desktop/Server project and create a
link to the file in a Silverlight project. DevForce will perform type mapping between tiers, so
as long as the namespace and type name are the same, you may place the type definition in
any assembly.
2. Make sure the type is serializable. If your type has a non-default constructor (in other
words a constructor which accepts arguments) then it is not serializable. You can easily
remedy this by either adding a default constructor or marking up the class with DataContract
and DataMember attributes so that you can specifically control which members are
serialized.
If a type which cannot be serialized is included as a known type the EntityServer service will not
start. You'll see a message in the server's debug log which states the service "cannot be activated
due to an exception during compilation." The message will also include the type at fault.
3. Make sure the type is somehow marked as a known type, given the information above on
how to indicate a known type.
Note that a type, T, and List<T> are not the same thing. If you return a List<T> from an RSM, then the
known type is List<T>, not T.
Also note that to the serializer, List<T> and T[] are different things, but they may
unfortunately have the same contract. Since DevForce automatically adds List<T> for most
primitive types to the known type list, you will receive an error if you add T[] for a primitive
type as a known type.
This also means that in queries with a contains clause you should use a List<T> and not T[].
Additional techniques

POCO
Last modified on March 16, 2011 13:32
Introduction
In addition to objects based on classes inheriting from IdeaBlade.EntityModel.Entity and
generated by the DevForce EDMX Extension, you can also use Plain Old CLR Objects
(POCOs) with DevForce.
For our purposes, a POCO class is any class that does not contain any DevForce specific
code.
Any POCO classes must be deployed on both the client and the server and must be contained
in one of the assemblies routinely searched by DevForce.
An additional POCO service provider, must be supplied server-side, marked with the
EnableClientAccess attribute. This class will contain methods to perform the server-side
CRUD operations for your custom objects.
For convenience, you will probably also want to deploy a client-side class containing
extension methods for the EntityManager, so that you can refer to your POCO objects in
LINQ queries in a manner similar to that which you use with your DevForce entities.
If the objects have an identified (primary) key value, they will operate fully as first-class
citizens in the DevForce local cache. That means, among other things, that they can be:
Stored in the cache;
Queried against and retrieved from the cache;
Updated in the cache;
Created in the cache; and of course
Saved from the cache.
Objects that do not have an identified key can still be retrieved, but will not be stored in the
DevForce cache.
Where possible we have adopted Microsoft's "RIA Services" naming conventions and
attributes.
POCO's and the EntityManager
Last modified on March 22, 2011 16:18
POCO entities are managed by DevForce in the same fashion as Entity Framework sourced
entities. The diagram below illustrates this. The DevForce EntityManager effectively
provides two categories of objects that it can host and provides 'almost' identical services to
both.


Implement a POCO class
Last modified on March 22, 2011 19:08
Contents
POCO class rules
Example
Other issues
A POCO class is a .NET class that has no visible dependencies on DevForce. In order for
DevForce to be able to query and save instances of such types there are a few simple
additional rules that need to be followed.


POCO class rules

POCO types must be "known" types. ( KnownType ) Indicating that a type is a "known" type
allows it to be discovered by the DevForce infrastructure.
There are several ways to identify the type as a "known" type to DevForce:
(1) Decorate a property (or multiple properties) of the class with the Key attribute; or
(2) Have the type implement the IKnownType interface; or
(3) Implement the IKnownTypeProvider interface.
POCO types without a Key attribute will NOT be added to the EntityManager cache and
cannot make use of EntityAspect semantics. This is because the EntityManager stores and
indexes entities by thier keys and therefore objects without key information cannot be
managed. Note that keyless POCO's are actually useful when you just want to bring down
temporary data for immediate processing and then throw it away. Because keyless POCO's
are not cached they will get garbage collected as soon as they go out of scope.


POCO types must be serializable.
1) Mark the class and members with the DataContract and DataMember attributes, or
2) The public properties of the class will be serializable if the class has a public
parameterless constructor. This technique is used below.
Implement INotifyPropertyChanged if you want EntityState management of your POCO
object. Note that you can always manage your POCO's EntityState manually ( described later)
if you would rather not implement INotifyPropertyChanged.
Example

POCO types are most commonly used to create entities that wrap data that is not stored in a
relational database.
Here is a class representing a State of the United States. At runtime, you might, for example,
create a collection of these state instance from an XML data file deployed on the server:
C#
using System;
using System.ComponentModel.DataAnnotations;

namespace DomainModel {

public class USState {
public USState() {
}

[Key]
public string Abbrev {
get { return _abbrev; }
set { _abbrev = value; }
}

public string Name {
get { return _name; }
set { _name = value; }
}

string _abbrev;
string _name;
}
}
VB
Imports System
Imports System.ComponentModel.DataAnnotations

Namespace DomainModel

Public Class USState

Public Sub New()
End Sub

<Key()>
Public Property Abbrev() As String
Get
Return _abbrev
End Get
Set(ByVal value As String)
_abbrev = value
End Set
End Property

Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property

Private _abbrev As String
Private _name As String
End Class
End Namespace
Note that we could have omitted the use of the Key attribute if we had made the class
implement the IKnownType interface.
C#
public class USState: IdeaBlade.EntityModel.IKnownType {
...
}
VB
Public Class USState
Implements IdeaBlade.EntityModel.IKnownType
...
End Class
This approach can be useful if you will have many classes that inherit from a base class, and
you wish only to mark the base class.
A third option is to implement the DevForce IKnownTypeProvider interface and return your
list of known types:
C#
public class KnownTypeProvider : IKnownTypeProvider {
public IEnumerable<Type> AddKnownTypes() {
return new Type[] { typeof(USState) }
}
}
VB
Public Class KnownTypeProvider
Implements IKnownTypeProvider
Public Function AddKnownTypes() As IEnumerable(Of Type)
Return New Type() { GetType(USState) }
End Function
End Class
Other issues
One issue that can arise is the need to mark up a type where the return type of one of the data
members is actually the base type of the object expected to be actually returned. In this case,
the KnownType attribute may be used to mark up a type with information about any of its
serializable members where the declared type of the member is different from the actual type
of the member.
Suppose, for example, that your State class includes a Cities property which is typed as an
object but actually returns a List<Cities>. This will confuse the serializer and make it serialize
the property improperly. To enable the property to be serialized properly, you must attribute it
as follows:
C#
[DataContract]
[KnownType(typeof(List<City>)]
public class State {
public State() {}
//[... snip]
[DataMember]
public object Cities {
get {
return _cities;
}
set {
_cities = value;
}
}

private List<City> _cities;
}
VB
<DataContract, KnownType(GetType(List(Of City))>
Public Class State
Public Sub New()
End Sub
'[... snip]
<DataMember>
Public Property Cities() As Object
Get
Return _cities
End Get
Set(ByVal value As Object)
_cities = value
End Set
End Property

Private _cities As List(Of City)
End Class
Note that the KnownType attribute used above is not a DevForce specific attribute but is part of
.NET's WCF serialization stack. It should not be confused with the DevForce IKnownType interface
also described above. The two, while both related to the concept of known types, are intended for
very different purposes.
Implement query and save services
Last modified on March 16, 2011 18:41
Contents
Example
In order to provide server side querying and saving capabilities for POCO objects, a POCO
Service Provider class or classes must be provided. This POCO Service Provider class can
be named anything and you may have many such classes.
The one rule is that each of these classes be marked with an EnableClientAccess attribute.


Example

The example below shows a simple POCO Service Provider, that provides the ability to
perform server side queries and saves against a collection of POCO instances of 'USState's.
C#
namespace DomainModel {

[EnableClientAccess]
public class USStatesServiceProvider {

public IEnumerable<USState> GetStates() {
...
}

public void InsertState(State entity) {
...
}

public void UpdateState(State current, State original) {
...
}

public void DeleteState(State entity) {
...
}
}
}
VB
Namespace DomainModel

<EnableClientAccess>
Public Class USStatesServiceProvider

Public Function GetStates() As IEnumerable(Of USState)
...
End Function

Public Sub InsertState(ByVal entity As State)
...
End Sub

Public Sub UpdateState(ByVal current As State, ByVal original As State)
...
End Sub

Public Sub DeleteState(ByVal entity As State)
...
End Sub
End Class
End Namespace
All of the actual method code is stubbed out in the example so that the overall structure can be
seen. Any of these methods can be omitted as long as the corresponding functionality is not
needed. So if we never planned on inserting, deleting or updating a 'USState' then the
InsertState, UpdateState and DeleteState methods could all be ommited. Details of how such
methods can be implemented are described later.
In the example below, the method names GetStates, InsertState, UpdateState, DeleteState are
all 'convention' based. More explicit linkage between service methods and the underlying
types can also be specified.



Provide query support
Last modified on April 22, 2011 17:33
Contents
Example
Finding providers by convention
The Query attribute alternative
Query methods with parameters
When to use parameterized query methods
rather than LINQ expressions
IQueryable Query methods
Include syntax is not supported for POCO queries
In order to provide server side support for POCO queries, a 'query' method or methods must
be supplied within a class marked with the EnableClientAccess attribute. Connecting these
server side methods to corresponding client side queries is handled either by 'convention'
based method naming or by explicit attribute markup.


Example

The example below shows a simple POCO Service Provider, that provides the ability to
perform server side queries against a collection of State POCO entities.
C#
namespace DomainModel {

[EnableClientAccess]
public class PocoServiceProvider {

public IEnumerable<State> GetStates() {
if ( _states == null) {
_states = ReadStatesData("states.xml");
}
return states;
}

private static IEnumerable<State> ReadStatesData(string embeddedFileName) {
...
}

private static List<State> _states = null;
}
}
VB
Namespace DomainModel

<EnableClientAccess>
Public Class PocoServiceProvider

Public Function GetStates() As IEnumerable(Of State)
If _states Is Nothing Then
_states = ReadStatesData("states.xml")
End If
Return states
End Function

Private Shared Function ReadStatesData(ByVal embeddedFileName As String) As
IEnumerable(Of State)
...
End Function

Private Shared _states As List(Of State) = Nothing
End Class
End Namespace
Finding providers by convention
The GetStates() method retrieves the data requested by a query (typically a query from the
client).
The method name is important. It follows the same query naming conventions that DevForce
uses to locate named query methods. In brief, DevForce looks for a method whose name
begins with a known prefix and is followed by an EntitySet name. The EntitySet name can be
anything that makes sense to you. Most developers use the plural of the POCO entity type
name.
Here are the recognized prefixes:
Get
Query
Fetch
Retrieve
Find
Select
The GetStates method conforms to the convention: "Get" is the prefix; "States" is the
EntitySet name.
The following query will be routed to the GetStates server-side query method:
C# var statesQuery = new EntityQuery<State>("States", anEntityManager);
VB Dim statesQuery = New EntityQuery(Of State)("States", anEntityManager)
The Query attribute alternative
The server method doesn't have to follow the naming convention. It can be named as you
please as long as it's adorned with the Query attribute.
C#
[Query]
public IEnumerable<State> ReturnAllStates() {
IEnumerable<State> states = ReadStatesData("states.xml");
return states;
}
VB
<Query()> _
Public Function ReturnAllStates() As IEnumerable(Of State)
Dim states As IEnumerable(Of State) = ReadStatesData("states.xml")
Return states
End Function
You must adjust the client-side query to specify the full method name as the EntitySet name:
C# var statesQuery = new EntityQuery<State>("ReturnAllStates", anEntityManager);
VB Dim statesQuery = New EntityQuery(Of State)("ReturnAllStates", anEntityManager)
Query methods with parameters
Methods with parameters are supported as well. For example, an additional overload to the
GetStates() method above that only returns states with a population size greater than a size
passed in might be written as shown below. (Naturally, this would require that the internal
ReadStatesData() method be modified as well.)
C#
public IEnumerable<State> GetStates(long minPopulationSize) {
IEnumerable<State> states = ReadStatesData("states.xml",
minPopulationSize);
return states;
}
VB
Public Function GetStates(ByVal minPopulationSize As Long) _
As IEnumerable(Of State)
Dim states As IEnumerable(Of State) = ReadStatesData("states.xml", _
minPopulationSize)
Return states
End Function
On the client side, parameters may be specified by using one of the
EntityQuery.AddParameter() overloads. The following snippet calls the parameterized
GetStates() method to return just those states with a population greater than one million
people:
C#
var query = new EntityQuery<State>("States", anEntityManager);
query.AddParameter(1000000);
VB
Dim query = New EntityQuery(Of State)("States", anEntityManager)
query.AddParameter(1000000)
Any number of query parameters are permitted, and the standard .NET overload resolution
rules apply. This means that the order and type of the parameters are checked to find
appropriate matches, with type coercion occurring as required.
When to use parameterized query methods
rather than LINQ expressions
The following two queries will return the same results:
C#
var query1 = new EntityQuery<State>("States", anEntityManager);
query.Where(state => state.Population > 1000000);

var query2 = new EntityQuery<State>("States", anEntityManager);
query.AddParameter(1000000);
VB
Dim query1 = New EntityQuery(Of State)("States", anEntityManager)
query.Where(Function(state) state.Population > 1000000)

Dim query2 = New EntityQuery(Of State)("States", anEntityManager)
query.AddParameter(1000000)
Furthermore, in both cases, the restriction to those states with greater than one million
population occurs on the server, not the client. So the question arises: is one to be preferred
over the other? The answer usually depends upon how the server-side method itself is
implemented.
In general, unless the server-side method can internally use the query parameter to restrict its
own query against some back-end data store, query parameters have no advantage over LINQ
query restrictions. In fact, LINQ queries are far more flexible and intuitive to work with under
most circumstances. Nevertheless, there will be cases where a back-end data stores ability to
optimize some queries will yield sufficient performance improvement to justify the use of
query parameters.
For example, consider the Windows file systems ability to search for files, given a path and
wildcards. While the same result could be accomplished via a server-side method that
returned all of the files in the file system and then iterated over them to locate a desired set of
files, it would likely be faster to call the file system directly with the path and wildcard
restrictions.
IQueryable Query methods
The GetStates POCO query returns an IEnumerable of State. That's fine for this example
because there are only 50 state objects and they are sourced from an XML file. The impact of
a State query on the server is small whether the client asks for one state or all states.
But what if the POCO is of type Order and we source orders from a database. If GetOrders
returns an IEnumerable<Order>, every time the client queries for orders the server retrieves
every order in the database. There could be millions of orders. Every client query would force
the server to retrieve those millions of orders.
Even a filtered client query such as
C#
var ordersQuery = new EntityQuery<Order>("Orders", anEntityManager).Where(o => o.OrderID
== 42);
VB
Dim ordersQuery = New EntityQuery(Of Order)("Orders", anEntityManager).Where(function (o)
o.OrderID = 42)
causes the server to first retrieve every order from the database and then filter down to the one
order with ID of 42. That's not going to perform well!
Suppose the Order data source can be queried with an IQueryable form of LINQ. Raw Entity
Framework can do it with LINQ-to-Entities; there is LINQ for NHibernate.
You then write an IQueryable<Order> GetOrders() query method on the server that returns
the LINQ query. DevForce appends the client's "Where" clause as before ... but now, when
the query is executed on the server, the query is composed such that the data source only
returns the one order.
The difference between IEnumerable and IQueryable bears repeating. Both example queries
return a single order to the client. The supporting IQueryable server-side query method
retrieves only one order from the database; the IEnumerable server-side query method
retrieves every order from the database before filtering down to the one desired order. That's a
huge performance - and scaling - improvement.
It pays to write POCO query methods that return IQueryable<T> when possible.
Include syntax is not supported for POCO queries

The Include() syntax on a POCO entity query is not currently implemented. The call will
compile but will not do anything.
Provide save support
Last modified on March 18, 2011 14:31
Contents
PocoSaveMode
Adapter-Based Saves
Convention-Based Saves
DevForce provides the ability to save POCO instances by dispatching save calls to a set of
server side interceptor methods. These methods come in two flavors and will be referred to
as either adapter-based or convention-based implementations. By default, DevForce will
attempt to locate an adapter-based implementation; if unsuccessful, it will then look for a
convention-based implementation.


PocoSaveMode
The implementation mechanism can also be specified explicitly by setting the PocoSaveMode
property of the SaveOptions instance passed into the SaveChanges call:
C#
var so = new SaveOptions();
so.PocoSaveMode = PocoSaveMode.UseEntitySaveAdapter;
myEntityManager.SaveChanges(so);
VB
Dim so = New SaveOptions()
so.PocoSaveMode = PocoSaveMode.UseEntitySaveAdapter
myEntityManager.SaveChanges(so)
The PocoSaveMode is an enumeration with the following values:
Value Description
Default
Use an EntitySaveAdapter subclass if found, otherwise use
save methods discovered via convention.
UseEntitySaveAdapter Use an implementation of EntityServerPocoSaveAdapter.
UseMethodsDiscoveredViaConvention Use methods discovered via convention.
Adapter-Based Saves
The adapter-based mechanism requires the existence of a server-side class that inherits from
the IdeaBlade.EntityModel.Server.EntityServerPocoSaveAdapter. If such a class is found, a
single instance of this class will be created for each SaveChanges call, and the appropriate
methods corresponding to each insert, update, or delete will be called for each entity to be
saved. A single null-parameter constructor is required.
The following bare-bones version of an EntitySaveAdapter implementation shows the
methods you have available to override:
C#
public class PocoSaveAdapter : EntityServerPocoSaveAdapter {
public PocoSaveAdapter() {
}

public override void BeforeSave(IEnumerable entities, SaveOptions saveOptions) {
}

public override void AfterSave() {
}

public override void InsertEntity(object entity) {
}

public override void UpdateEntity(object entity, object originalEntity) {
}

public override void DeleteEntity(object entity) {
}
}
VB
Public Class PocoSaveAdapter
Inherits EntityServerPocoSaveAdapter
Public Sub New()
End Sub

Public Overrides Sub BeforeSave(ByVal entities As IEnumerable, ByVal saveOptions As
SaveOptions)
End Sub

Public Overrides Sub AfterSave()
End Sub

Public Overrides Sub InsertEntity(ByVal entity As Object)
End Sub

Public Overrides Sub UpdateEntity(ByVal entity As Object, ByVal originalEntity As Object)
End Sub

Public Overrides Sub DeleteEntity(ByVal entity As Object)
End Sub
End Class
Note that a single insert, update, or delete method handles saves for every entity type, so if
save logic needs to be different for different types, the type of the entity passed in will need to
be inspected and the execution branched appropriately.
The BeforeSave and AfterSave methods are called exactly once for each SaveChanges call
and may be used for 'setup' and 'teardown' logic.
Convention-Based Saves
The convention-based mechanism requires the existence of a server-side class with the
EnableClientAccess attribute. This class will include insert, update, and delete methods
named according to the conventions defined below. It must also include a single null-
parameter constructor.
If such a class is found, a single instance of it will be created for each SaveChanges call, and
the appropriate methods corresponding to each insert, update, or delete will be called for each
entity to be saved.
For each type for which a persistence operation is provided, up to three methods must be
written. The name of the method must begin with one of the prefixes defined below. The
method must also conform to the signature defined below.
If you do not expect to save objects that require one or more of these signatures, then they do
not have to be implemented. In other words, if you never plan to delete Foo type objects,
then you do not need to implement the Delete method.
Insert Method
Prefixes: Insert, Add, or Create
Signature: void InsertX(T entity), where T is an entity Type
Update Method
Prefixes: Update, Change, or Modify
Signature: void UpdateX(T current, T original), where T is an entity Type
Delete Method
Prefixes: Delete or Remove
Signature: void DeleteX(T entity), where T is an entity Type
Below is an example implemention showing the use of the required conventional method
names and signatures. InsertFoo could equally be named AddFoo or CreateFoo;
UpdateFoo could be named ChangeFoo or ModifyFoo; and so forth.
C#
[EnableClientAccess]
public class PocoSaveAdapterUsingConventions {
public PocoSaveAdapterUsingConventions() {
}
public void InsertFoo(Foo entity) {
// insert logic for any Foo entities
}
public void InsertBar(Bar entity) {
// insert logic for any Bar entities
}
public void UpdateFoo(Foo current, Foo original) {
// update logic for any Foo entities
}
public void UpdateBar(Bar current, Bar original) {
// update logic for any Bar entities
}
public void DeleteFoo(Foo entity) {
// Delete logic for any Foo entities
}
public void DeleteBar(Bar entity) {
// Delete logic for any Bar entities
}
}
VB
<EnableClientAccess()> _
Public Class PocoSaveAdapterUsingConventions
Public Sub New()
End Sub
Public Sub InsertFoo(ByVal entity As Foo)
' insert logic for any Foo entities
End Sub
Public Sub InsertBar(ByVal entity As Bar)
' insert logic for any Bar entities
End Sub
Public Sub UpdateFoo(ByVal current As Foo, ByVal original As Foo)
' update logic for any "Foo entities
End Sub
Public Sub UpdateBar(ByVal current As Bar, ByVal original As Bar)
' update logic for any "Bar entities
End Sub
Public Sub DeleteFoo(ByVal entity As Foo)
' Delete logic for any "Foo entities
End Sub
Public Sub DeleteBar(ByVal entity As Bar)
' Delete logic for any "Bar entities
End Sub
End Class

Make your POCO query a first class citizen
Last modified on March 24, 2011 00:09
Contents
Create the query directly
Create an extension method
Extend your strongly typed EntityManager partial class
Querying for POCO entities from the client-side involves exactly the same process as is used
for non-POCO entities, with the single exception that DevForce will not generate a 'root'
property on your EntityManager to start your queries from. There are three ways around this:


Create the query directly
Your first choice is to simply bypass the idea of a 'root' query property on your
EntityManager and create the query directly.
C#
var baseQuery = new EntityQuery<USState>("USStates", anEntityManager);
var queryForstatesStartingWithA = query.Where(s => s.Abbrev.StartsWith("A");
VB
Dim baseQuery = New EntityQuery(Of USState)("USStates", anEntityManager)
Dim queryForstatesStartingWithA = query.Where(Function(s) s.Abbrev.StartsWith("A")
Create an extension method
The next choice is to create an extension method that adds a "USStates" method to every
EntityManager.
For example:
C#
namespace DomainModel {
public static class EmExtensions {
public static EntityQuery<USState> USStates(this EntityManager em) {
return new EntityQuery<USState>("USStates", em);
}
}
}
VB
Namespace DomainModel
Public Module EmExtensions
<System.Runtime.CompilerServices.Extension> _
Public Function States(ByVal em As EntityManager) As EntityQuery(Of USState)
Return New EntityQuery(Of USState)("USStates", em)
End Function
End Module
End Namespace
With this extension method, you can now query for USStates with the following syntax:
C#
var queryForstatesStartingWithA = anEntityManager.USStates().Where(s =>
s.Abbrev.StartsWith("A"));
VB
Dim queryForstatesStartingWithA = _
anEntityManager.USStates().Where(Function(s) s.Abbrev.StartsWith("A"))
This is very similar to what you do with DevForce entities, except that, since USStates is an
extension method, you will have to include the parentheses -- anEntityManager.States(),
which you do not have to do with autogenerated query properties. ie.
anEntityManager.USStates.Where()
Extend your strongly typed EntityManager partial class

An obvious alternative to this process is to add a "USStates" property to your own "custom"
partial class that extends your strongly typed EntityManager. This makes "USStates" exactly
like any other "root" entity query available from the EntityManager, but does require
duplicate code if you expect to use "States" from a different strongly typed EntityManager.
C#
public partial class DomainModelEntityManager : IdeaBlade.EntityModel.EntityManager {
public EntityQuery<USState> USStates {
get { return new EntityQuery<USState>("USState", this); }
}
}
VB
Partial Public Class DomainModelEntityManager
Inherits IdeaBlade.EntityModel.EntityManager
Public ReadOnly Property USStates() As EntityQuery(Of USState)
Get
Return New EntityQuery(Of USState)("USState", Me)
End Get
End Property
End Class
Note that you can extend the queries with clauses with the full set of LINQ extension methods
-- such as Where(), used above -- just as you can do with ordinary queries
Obtain access to entity services
Last modified on March 21, 2011 17:37
Contents
Access to EntityAspect
Wrap your POCO
Implementing IHasEntityAspect
Why does implementing IHasEntityAspect improve performance?
Objects from DevForce-generated Entity classes have an EntityAspect property through which
a number of important operations and useful pieces of metadata can be obtained. POCO
objects, by their nature do not have such a property. There are, however, other ways to get
access to such services.


Access to EntityAspect
In order to get an EntityAspect for any POCO entity, there are two choices:
Wrap your POCO entity at runtime with a class that provides access to EntityAspect services.
Implement the IHasEntityAspect interface on your POCO entity.
o The downside of this is that your POCO entity is not longer a 'pure' POCO entity
because you will have added DevForce specific code to it.
o The upside is that your POCO entities have an EntityAspect property just like any
other DevForce entity and performance is improved.
Wrap your POCO

The EntityWrapper.Wrap static method may be used to get access to a runtime wrapper that
provides an EntityAspect property.
C# var stateWithAspect = EntityWrapper.Wrap(aState);
VB Dim stateWithAspect = EntityWrapper.Wrap(aState)
Having done that, you can then ask questions like the following
C# bool isModified = stateWithAspect.EntityAspect.IsModified();
VB Dim isModified As Boolean = stateWithAspect.EntityAspect.IsModified()
and of course, use any of the other facilities of the EntityAspect.
Implementing IHasEntityAspect
The IHasEntityAspect is a very simple interface that contains a single property of type
EntityAspect. To add this implementation to any given POCO type simply mark the class with
the interface and add a EntityAspect property with a default 'getter' and 'setter' as shown
below:
C#
public class USState : IHasEntityAspect {
//*snip+
[IgnoreDataMember]
public EntityAspect EntityAspect {
get;
set;
}
}
VB
Public Class USState _
Implements IHasEntityAspect
'*snip+
<IgnoreDataMember> _
Public Property EntityAspect() As EntityAspect
End Class
Once you have implemented this interface, your POCO entity will have direct access to this
'new' EntityAspect property, and DevForce will insure that it is properly initialized and
configured.
Note that we have included the IgnoreDataMember attribute to the EntityAspect property we
just created. Basically we are telling WCF that we do NOT want the EntityAspect property to
be serialized.
Use of this attribute is only necessary if we are relying on default WCF serialization, i.e. we
are not marking up our POCO entity with DataContract and DataMember attributes. If we are
using DataContract and DataMember attributes then we simply need to make sure not to
mark this property with a DataMember attribute.
Why does implementing IHasEntityAspect improve performance?

DevForce has to keep track of its own bookkeeping data about each POCO instance. By
default, DevForce uses a hashtable to maintain this data, and therefore needs to perform a
lookup operation anytime you need access to any EntityAspect services.
What the IHasEntityAspect interface does is provide a place for DevForce to keep its own
bookkeeping data about each POCO instance on the instance itself, hence no need for the
hashtable or the lookup.
POCO summary - Things to remember
Last modified on March 16, 2011 13:34
POCO classes must be included in both the server- and client-side assemblies. Put them in
the server-side project and link them into the client-side project.
Include a POCO ServiceProvider class server-side.
Include EntityManager extensions client-side.
You can use all forms of LINQ query against these objects.
If your POCO class has a primary key (designated with the [Key] attribute, instances of it will
be stored in the EntityManager cache, and can be updated, deleted, or inserted there.
If your POCO class has no key, instances can be retrieved but will not be placed in the
EntityManager cache.
Implement IHasEntityAspect to get EntityAspect property and associated functionality on
your almost POCO entity.

OData
Last modified on June 08, 2011 14:17
DevForce 6.0.7 or later provides the ability to expose a domain model through the Open Data
Protocol (OData). OData is an open web protocol for querying and updating data. The
protocol allows for a consumer to query a datasource over the HTTP protocol and get the
result back in formats like Atom, JSON or plain XML, including pagination, ordering or
filtering of the data. For more information on OData and client libraries for various platforms,
visit www.odata.org.
Prerequisites
DevForce 6.0.7
Code sample
Learn how to enable OData with this code sample. The complete walkthrough is available
here.
Enabling OData
Last modified on March 25, 2011 13:04
Contents
Getting started
Connecting to the data
Enabling OData
Enabling OData for a DevForce model allows for non .NET clients to access the same back-
end as your DevForce .NET clients. The programming model will be different from DevForce
and depends on the OData client implementation on the chosen platform, but it avoids the
need for developing yet another back-end or at a minimum some sort of a translation layer in
front of the DevForce back-end.
In this topic, we will demonstrate how to expose a DevForce domain model through OData
and access it from a client.
Note: DevForce 6.0.7 or later is required for this tutorial.
Getting started
Lets begin by creating a new project. Well be using Visual Studio 2010 and creating a Web
Application.
Create a new project by selecting DevForce BOS Web Application from the New Project
window.


The template creates one project for us.
The DevForce BOS Web Application is the middle tier of a typical n-tier DevForce
application. At the end of this tutorial it will be able to serve regular DevForce clients as well
as OData clients.
Connecting to the data
In this tutorial, we are going to use our usual suspect, the NorthwindIB database. At this stage
we are assuming basic familiarity with how to create a data model using ADO.NET Entity
Framework. If you are not familiar with creating a data model, please complete one of our
intro tutorials first.
We want to name the model NorthwindIB, generate it from the database and select only the
Customer and Order tables to keep it small and manageable.
If everything went well, the result should look like this:


Enabling OData
For all intents and purposes, at this point we have a functioning DevForce back-end and could
start building a DevForce client application. Instead, we are going to expose this back-end via
OData with a two-step process.

For the first step, we need to enable OData in our domain model.
Open NorthwindIB.edmx and click anywhere in the whitespace to select the model, then hit
F4 to bring up the model properties. Under the DevForce Code Generation category you
will find a new option called OData Enabled. By default the option is set to False. Go ahead
and change it to True, then save.


Lets look at what this option did for us. First, it added a couple of attributes to our Entity
classes to make them usable in a WCF Data Service. Second, it generated a partial class for
our strongly typed EntityManager.
Open NorthwindIBEntities_IUpdatable.cs. In this file, youll find an implementation of
System.Data.Services.IUpdatable. The WCF Data Service calls upon this implementation to
handle the CUD operations. This file gets generated only once, so you can make
customization without having to worry about them getting wiped out.
Now, whats this WCF Data Service? The WCF Data Service is part of the .NET framework
and handles all the OData mechanics. In order for the WCF Data Service to do its magic, it
requires a compatible data container, which provides the actual data and supports optional
updates. Enabling OData in our data model turned the EntityManager into just such a
container. The implementation of System.Data.Services.IUpdatable handles the optional
updates.
So, for the second step we need to add a WCF Data Service to our project. Right-click on the
ODataTour project and select Add | New Item....
In the Add New Item dialog, you will find the WCF Data Service under Web. We'll name
ours ODataService and click Add.


If you receive the following message, open the web.config file and change
aspNetCompatibilityEnabled to true.


We are not quite done yet. We need to complete the WCF Data Service.
Open ODataService.svc.cs and modify the code as follows:
C#
public class ODataService : DataService<NorthwindIBEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service operations are visible, updatable,
etc.
// Examples:
// config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
// config.SetServiceOperationAccessRule("MyServiceOperation", ServiceOperationRights.All);

config.SetEntitySetAccessRule("Customers", EntitySetRights.All);
config.SetEntitySetAccessRule("Orders", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
}
}
VB
Public Class ODataService
Inherits DataService(Of NorthwindIBEntities)
' This method is called only once to initialize service-wide policies.
Public Shared Sub InitializeService(ByVal config As _
DataServiceConfiguration)
' TODO: set rules to indicate which entity sets and
' service operations are visible, updatable, etc.
' Examples:
' config.SetEntitySetAccessRule("MyEntityset", EntitySetRights.AllRead);
' config.SetServiceOperationAccessRule("MyServiceOperation",
' ServiceOperationRights.All);

config.SetEntitySetAccessRule("Customers", EntitySetRights.All)
config.SetEntitySetAccessRule("Orders", EntitySetRights.All)
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2
End Sub
End Class
Lets look at the above code. First, we specified our EntityManager as the data container for
the service by providing it as the generic data type on the DataService<T> base class. Second,
weve specified that both of our entity sets, customers and orders are visible and updatable.
At this point we are ready to test our service. Right-click ODataService.svc and select View
in Browser. If everything went well, you should receive the standard service definition
response like this:


This response tells us that we have two entity sets as expected. So, lets see if we can actually
query some data.
Enter the following URL in the browsers address bar:
http://localhost:9009/ODataService.svc/Customers
Depending on the browser, youll have to view source in order to see the raw response.
At this point, our OData service can be consumed by any client that supports OData.

Call server methods
Remote server method call (RSMC)
Last modified on June 01, 2011 15:03
Contents
How to define a Remote Server Method
Method signature
How to call a Remote Server Method from the client
How to secure a Remote Server Method
Code samples
Troubleshooting
A Remote Server Method is a server-side method that is defined and deployed in an assembly
on the server. This type of method can return any serializable object and can pass any
serializable parameters. Typically server-side methods are used to batch several queries and
other actions which might otherwise be too slow if called one-by-one from the client
application.


How to define a Remote Server Method
Here are the rules when defining a Remote Server Method.
1) The method signature must conform to the ServerMethodDelegate.
C#
public static Object ServerMethodDelegate(IPrincipal principal,
EntityManager entityManager, params Object[] args);
VB
Public Shared Function ServerMethodDelegate(principal As IPrincipal,_
entityManager As EntityManager, ParamArray args As Object()) As Object
End Function
2) You have to apply the [AllowRpc] attribute to the method.
3) All types passed as arguments and as the return value must be simple types or primitives or
must meet the requirements for known types.
Method signature
Both the IPrincipal and EntityManager are provided to the method by DevForce, they are not
passed from the client.
IPrincipal - The IPrincipal passed to the method is the IPrincipal associated with the user of
the client application, and is the same IPrincipal returned by the EntityManager.Login call.
EntityManager - The EntityManager passed into the method is an empty server-side
EntityManager constructed by DevForce specifically for the method call. This
EntityManager does not need to be logged in, and may be used to issue queries and saves.
params Object[] args - To pass any argument to be used inside the server method.
How to call a Remote Server Method from the client
You can invoke a server method from the client synchronously or asynchronously:
InvokeServerMethod
InvokeServerMethodAsync
If you call the weakly typed overload (using strings for the type and method names), make
sure that the type name is fully qualified like: MyNamespace.MyType, MyAssembly.
If you call the strongly typed overload (using a delegate), make sure that the delegate is
available on the client in an assembly with the same name as the server.
How to secure a Remote Server Method
Please see here for more details.
Code samples
1) Define the server method.
C#
namespace DomainModel {
public class ServerMethods {

[AllowRpc]
public static int GetNumberOfOrders(IPrincipal principal,
EntityManager entityManager, params Object[] args) {

// Gather args
DateTime startDate = (DateTime) args[0];
DateTime endDate = (DateTime) args[1];

// Query and get the count
int count = entityManager.GetQuery<OrderSummary>()
.Where(os => os.OrderDate > startDate && os.OrderDate < endDate)
.Count();

return count;
}
}
}
VB
Namespace DomainModel
Public Class ServerMethods

<AllowRpc> _
Public Shared Function GetNumberOfOrders(principal As IPrincipal,_
entityManager As EntityManager, ParamArray args As Object()) As Integer

' Gather args
Dim startDate As DateTime = DirectCast(args(0), DateTime)
Dim endDate As DateTime = DirectCast(args(1), DateTime)

' Query and get the count
Dim count As Integer = entityManager.GetQuery(Of OrderSummary)()_
.Where(Function(os) os.OrderDate > startDate AndAlso os.OrderDate < endDate)_
.Count()

Return count
End Function
End Class
End Namespace
2) Call the server method passing fullTypeName and methodName.
C#
public int GetOrderCount(DateTime startDate, DateTime endDate) {
string typeName = "DomainModel.ServerMethods, DomainModel";
string methodName = "GetNumberOfOrders";
return (int)_entityManager.InvokeServerMethod(typeName, methodName, startDate, endDate);
}
VB
Public Function GetOrderCount(startDate As DateTime, endDate As DateTime) As Integer
Dim typeName As String = "DomainModel.ServerMethods, DomainModel"
Dim methodName As String = "GetNumberOfOrders"
Return CInt(_entityManager.InvokeServerMethod(typeName, methodName, startDate,
endDate))
End Function
3) Call the server method using ServerMethodDelegate.
C#
public int GetOrderCount(DateTime startDate, DateTime endDate) {
var serverMethod = new ServerMethodDelegate(ServerMethods.GetNumberOfOrders);
return (int)_entityManager.InvokeServerMethod(serverMethod, startDate, endDate);
}
VB
Public Function GetOrderCount(ByVal startDate As Date, ByVal endDate As Date) As Integer
Dim serverMethod = New ServerMethodDelegate(ServerMethods.GetNumberOfOrders)
Return CInt(_entityManager.InvokeServerMethod(serverMethod, startDate, endDate))
End Function
Troubleshooting
So you've followed the setup information above, yet it's just not working. Maybe it looks like
the method call is hanging, or maybe an indecipherable error message is returned.
1) Check the debug log for warning and informational messages. DevForce will log an
informational message about every known type found, and every remote server
method. Logging of the remote server methods is done lazily, as the methods are called, but
if DevForce thinks the return type will be a problem it will write a warning to the log.
2) Add a try/catch around your sync call, or check the InvokeServerMethodOperation error
returned from the asynchronous call. We try to intercept the underlying error (which is
almost always a CommunicationException or SerializationException) and provide some more
helpful information, but it's not always easy. Check the InnerException too. Exceptions with
the InvokeServerMethod are almost always due to a problem with either the input or output
types, so walk through the requirements above to ensure you haven't missed anything.
3) What if you're passing or returning a complex type, over which you have no control? Wrap
the type in another simple class (or a struct as of release 6.0.7) and make sure that simple type
meets all the serialization/known type requirements.
Subscribe to a pub-sub service
Last modified on June 21, 2011 16:13
Contents
Define a push service
o Method signature
Subscribe to a push service
o Pass arguments with the subscription
Send notifications
Receive notifications
Configure the push service
o Learn more
Push notification allows client applications to subscribe to user-defined services on the
EntityServer and to receive notifications from the server when an event of interest occurs. The
push service runs on its own thread and can perform any processing desired, including starting
additional threads or processes. The method is started upon first client subscription, and
stopped after the last client unsubscribes.
The push service is similar to the server-side method used by the InvokeServerMethod() call
with the difference that while the latter is a request-response method call, the push service can
run indefinitely and support any number of subscribing clients. The push feature may be an
option if your invoked server method is timing out due to lengthy processing requirements.


Define a push service
The class holding your service's entry method should be in an assembly deployed to the
EntityServer. In addition, the method must meet the following criteria:
1) The method signature must conform to the ServerNotifyDelegate;
C#
public delegate void ServerNotifyDelegate(Guid serviceKey,
INotificationManager notificationManager,
EntityManager serverEntityManager);
VB
Public Delegate Sub ServerNotifyDelegate(ByVal serviceKey As Guid, _
ByVal notificationManager As INotificationManager, _
ByVal serverEntityManager As EntityManager)
2) The method must be decorated with the [AllowRpc] attribute and must be static;
Here's an example:
C#
[AllowRpc]
public static void MultiStepService(Guid serviceKey,
INotificationManager notificationManager,
EntityManager entityManager)
{
// ...
}
VB
<AllowRpc>
Public Shared Sub MultiStepService(ByVal serviceKey As Guid, _
ByVal notificationManager As INotificationManager, _
ByVal entityManager As EntityManager)
' ...
End Sub
Method signature
All three parameters are provided to the method by DevForce.
serviceKey - Server-assigned key which uniquely identifies this service.
notificationManager - The INotificationManager used to obtain subscriber information and
send notifications to client subscribers.
serverEntityManager - A server-side EntityManager.
Subscribe to a push service
To subscribe to a push service, the client must call the EntityManagers RegisterCallback
method:
C#
_entityManager.RegisterCallback(
"DomainModel.LongRunningProcedure, DomainModel", /* Type name */
"MultiStepService", /* Method name */
LongRunningProcedureNotification, /* the callback */
"lrp"); /* user token */
VB
_entityManager.RegisterCallback( _
"DomainModel.LongRunningProcedure, DomainModel", _
"MultiStepService", _
LongRunningProcedureNotification, _
"lrp")
' user token - the callback - Method name - Type name
Once registered, the client remains subscribed to the service until either closing or calling
CancelCallback.
Pass arguments with the subscription
You can also pass user-defined arguments to the push service when registering. Here's a
sample passing a single parameter:
C#
_entityManager.RegisterCallback(
"DomainModel.OrderWatcher, DomainModel", /* Type name */
"NewOrderService", /* Method name */
OrderPushCallback, /* the callback */
_owToken, /* user token */
employeeId); /* client argument(s) */
VB
_entityManager.RegisterCallback( _
"DomainModel.OrderWatcher, DomainModel", _
"NewOrderService", _
OrderPushCallback, _
_owToken, _
employeeId)
' client argument(s) - user token - the callback - Method name - Type name
You can pass any number of arguments, but all types must be serializable, defined on both the
client and server, and known types.
These arguments are available in the push service on the NotificationSubscriber. The service
can retrieve all subscribers by calling the GetSubscribers method on the NotificationManager,
passing the assigned service key:
C#
foreach (var subscriber in __notificationManager.GetSubscribers(__serviceKey)) {
// Obtain arguments passed from client when registering.
var args = subscriber.ClientArguments;
// ...
}
VB
For Each subscriber In __notificationManager.GetSubscribers(__serviceKey)
' Obtain arguments passed from client when registering.
Dim args = subscriber.ClientArguments
' ...
Next subscriber
Send notifications
When the service has a notification to send to one or more subscribers, it does so with the
Send method on the NotificationManager.
To broadcast to all subscribers:
C# __notificationManager.Send(__serviceKey, "Some message here", "And another"));
VB __notificationManager.Send(__serviceKey, "Some message here", "And another"))
To send a notification to a specific subscriber, pass the NotificationSubscriber with the Send
call:
C# __notificationManager.Send(__serviceKey, subscriber, "One message", "And a second");
VB __notificationManager.Send(__serviceKey, subscriber, "One message", "And a second")
You can pass any number of notification arguments to clients, and they can be of any
type. As with the client arguments on the subscription, these types must be defined on both
client and server, serializable, and identified as known types.
Receive notifications
On the client, the notifications will be received by the callback method which was specified
when registering for the service. The callback method takes a SubscriptionOperation which
will indicate if an error occurred or contain a NotificationData array containing the data sent
from the server.
C#
private void OrderPushCallback(SubscriptionOperation op) {
// Get the first argument and display.
string msg = op.NotificationData[0].ToString();
MessageBox.Show(msg, "Received from OrderWatcher", MessageBoxButton.OK);
VB
Private Sub OrderPushCallback(ByVal op As SubscriptionOperation)
' Get the first argument and display.
Dim msg As String = op.NotificationData(0).ToString()
MessageBox.Show(msg, "Received from OrderWatcher", MessageBoxButton.OK)
End Sub
}

Configure the push service
1) Server
To be able to use the push feature, you must first enable it on the server. You can use
DevForce default settings by simply setting the following flag in the ideablade.configuration
section of the servers config file:
<notificationService enabled="true" />
You can also customize this configuration by defining the service endpoints in the
system.serviceModel section of the config file, or implementing a custom ServiceHostEvents
class.
2) Client
a) WinClient applications
You must specify the client port number in the ideablade.configuration section of the
app.config file:
<notificationService clientPort="9012"/>
Choose an port number not already in use, and be sure to open the port in your
firewall. If you need to customize the default configuration you can fully define the push
endpoint in the serviceModel section of the configuration file, or implement a custom
ServiceProxyEvents class.
b) Silverlight
In Silverlight applications, no configuration information in the app.config is provided. If
you need to customize the default configuration you can fully define the push endpoint in the
ServiceReferences.ClientConfig file, or implement a custom ServiceProxyEvents class.
Learn more
Push samples with additional configuration information
Sample configuration files - The push endpoints and default bindings are shown.

Patterns and practices
Last modified on March 23, 2011 15:38
You'll find a variety of patterns and practices, organized by associated client application,
model, or controller. These downloadable examples should be used to help improve your
understanding of how DevForce will improve your development experience.
You may also find more specific code samples that address more specific problems helpful as
well.
Create subordinate entities via the Root entity
Last modified on April 14, 2011 10:23
Contents
Introduction to Aggregates
Only the Root can create internal entities
CreateLineItem example
Only the Root entity of an Aggregate should be able to create other members of the
Aggregate. The Root should have a Create method for each member. Member classes should
be written such that only the root entity can create them. The Order and its LineItems is the
canonical example of an Aggregate. This topic introduces the vocabulary of aggregates and
explains how to implement the member Create methods.


Introduction to Aggregates
Entities typically cluster into Aggregates in which one entity is the designated Root and the
others are subordinate internal members. The root should control all access to the internal
members.
An Order entity and its LineItem entities constitute an "Order Aggregate". The Order is the
Root of the aggregate; the LineItems are its internal, subordinate members.
From the domain perspective, the Order and its LineItems are one thing, a conceptual Order,
represented by the concrete root Order entity. The LineItems have no meaningful existence
apart from their parent Order. You expect to get them from the Order; you wouldn't try to
query for them independently of their parent order.
A new, deleted, or changed LineItem is a modification of the Order Aggregate as surely as
changing the Order date. You make this insight tangible by observing the following rule:
when you would save a LineItem, you save its (modified) parent Order entity at the same
time. They travel together in the same transactional package.
Speaking of transaction, the root Order entity is the keeper of the "lock" or "concurrency
property" for the Aggregate as a whole. Because the Order is always part of the save
transaction and is always modified when any part of the aggregate is modified, concurrency
conflicts are detected and resolved with the root Order entity.
Only the Root can create internal entities
When you adopt this way of thinking, you realize that LineItems cannot be created directly.
Only the parent Order should be allowed to create them. It follows that:
1) The Order class should have a CreateLineItem method.
2) You should block attempts to create a OrderDetail directly by making all OrderDetail
constructors internal.
It also follows that you must ask the parent Order to delete or remove a member LineItem. You
should not be able to delete a LineItem directly; you must go through its parent Order.
CreateLineItem example

Replace unpredictable DateTime and Guid classes
Last modified on June 22, 2011 13:58
Contents
The problem
SystemTime
SystemGuid
Make your own system utility classes
Add system utility classes like SystemTime and SystemGuid to your application so you can
test component behaviors that are otherwise sensitive to unpredictable values coming from the
system environment (e.g., the current time or a new Guid).


The problem
.NET environment functions typically return values that come from the operating system such
as DateTime.Now and Guid.NewGuid(). These values are different everytime which
complicates repeatable testing.
You can control these values if you replace calls to the .NET functions with calls to similar
functions in system utility classes that you wrote. These utility classes behave like the .NET
functions under normal conditions but you can change their behavior during testing.
SystemTime
DateTimeis especially problematic for testers who want to validate logic that is time
sensitive. Suppose you had business logic that expected something to happen three days from
now. You certainly don't want a three-day test.
You can write a SystemTime class such as the one included below. SystemTime has Now()
and Today() methods that return a DateTime. If you do nothing, they behave exactly like
DateTime.Now and DateTime.Today.
Now everywhere in your application you always call SystemTime.Now() and
SystemTime.Today() wherever you would have called DateTime.Now and DateTime.Today.
If you do nothing, the behavior of your application is unchanged.
During a test, however, you can replace the SystemTime.NowFn with a test-time function that
returns any DateTime value you need.
Remember when you are done to restore NowFn to the proper default behavior. A
"ResetNowFn" method makes that easier for testers.
C#
/// <summary>
/// Replacement for <see cref="DateTime"/>
/// ** ALWAYS USE THIS INSTEAD OF CALLING DATETIME DIRECTLY
/// </summary>
/// <remarks>
/// Covers the <see cref="DateTime"/> static methods so that
/// test and development scenarios can reset the "Current" time
/// to whatever they like. See <see cref="NowFn"/>.
/// TODO: Extend to support UtcNow
/// </remarks>
public static class SystemTime {

/// <summary>
/// Gets a <see cref="DateTime"/> that is set to the "current" date and time
/// in the manner of <see cref="DateTime.Now"/>.
/// See <see cref="NowFn"/>.
/// </summary>
public static DateTime Now() { return NowFn(); }

/// <summary>
/// Gets "current" date
/// in the manner of <see cref="DateTime.Today"/>.
/// See <see cref="NowFn"/>.
/// </summary>
public static DateTime Today() {
var now = Now();
return now-now.TimeOfDay;
}

/// <summary>
/// Function for getting the "current" date and time.
/// Defaults to <see cref="DateTime.Now"/> but
/// could be replaced in a test or development scenario.
/// </summary>
public static Func<DateTime> NowFn = () => DateTime.Now;

/// <summary>
/// Reset <see cref="NowFn"/> to application default
/// </summary>
public static void ResetNowFn() { NowFn = () => DateTime.Now; }
}
VB
''' <summary>
''' Replacement for <see cref="DateTime"/>
''' ** ALWAYS USE THIS INSTEAD OF CALLING DATETIME DIRECTLY
''' </summary>
''' <remarks>
''' Covers the <see cref="DateTime"/> static methods so that
''' test and development scenarios can reset the "Current" time
''' to whatever they like. See <see cref="NowFn"/>.
''' TODO: Extend to support UtcNow
''' </remarks>
Public NotInheritable Class SystemTime

''' <summary>
''' Gets a <see cref="DateTime"/> that is set to the "current" date and time
''' in the manner of <see cref="DateTime.Now"/>.
''' See <see cref="NowFn"/>.
''' </summary>
Private Sub New()
End Sub
Public Shared Function Now() As Date
Return NowFn()
End Function

''' <summary>
''' Gets "current" date
''' in the manner of <see cref="DateTime.Today"/>.
''' See <see cref="NowFn"/>.
''' </summary>
Public Shared Function Today() As Date
Dim now = SystemTime.Now()
Return now-now.TimeOfDay
End Function

''' <summary>
''' Function for getting the "current" date and time.
''' Defaults to <see cref="DateTime.Now"/> but
''' could be replaced in a test or development scenario.
''' </summary>
Public Shared NowFn As Func(Of Date) = Function() Date.Now

''' <summary>
''' Reset <see cref="NowFn"/> to application default
''' </summary>
Public Shared Sub ResetNowFn()
NowFn = Function() Date.Now
End Sub
End Class
SystemGuid
Guid.NewGuid() returns a new and deliberately unpredictable value every time. You may
find yourself writing a test where you would like to control the value of that new Guid.
You can write a SystemGuid class such as the one included below. SystemGuid has a
NewGuid() method that return a Guid. If you do nothing, it behaves exactly like
Guid.NewGuid().
Now everywhere in your application you always call SystemGuid.NewGuid() wherever you
would have called Guid.NewGuid.
If you do nothing, the behavior of your application is unchanged.
During a test, however, you can replace the SystemGuid.NewGuidFn with a test-time function
that returns any Guid value you need.
Remember when you are done to restore NewGuidFn to the proper default behavior. A
"ResetNewGuidFn" method makes that easier for testers.
C#
public static class SystemGuid
{
/// <summary>
/// Gets a new <see cref="Guid"/>
/// in the manner of <see cref="Guid.NewGuid"/>.
/// See <see cref="NewGuidFn"/>.
/// </summary>
public static Guid NewGuid() { return NewGuidFn(); }

/// <summary>
/// Function for getting a new <see cref="Guid"/>.
/// Defaults to <see cref="Guid.NewGuid"/> but
/// could be replaced in a test or development scenario.
/// </summary>
public static Func<Guid> NewGuidFn = Guid.NewGuid;

/// <summary>
/// Reset <see cref="NewGuidFn"/> to application default
/// </summary>
public static void ResetNewGuidFn() { NewGuidFn = Guid.NewGuid; }

}
VB
Public NotInheritable Class SystemGuid
''' <summary>
''' Gets a new <see cref="Guid"/>
''' in the manner of <see cref="Guid.NewGuid"/>.
''' See <see cref="NewGuidFn"/>.
''' </summary>
Private Sub New()
End Sub
Public Shared Function NewGuid() As Guid
Return NewGuidFn()
End Function

''' <summary>
''' Function for getting a new <see cref="Guid"/>.
''' Defaults to <see cref="Guid.NewGuid"/> but
''' could be replaced in a test or development scenario.
''' </summary>
Public Shared NewGuidFn As Func(Of Guid) = Guid.NewGuid

''' <summary>
''' Reset <see cref="NewGuidFn"/> to application default
''' </summary>
Public Shared Sub ResetNewGuidFn()
NewGuidFn = Guid.NewGuid
End Sub

End Class
Make your own system utility classes
Look for other places in your application where you call a .NET static function or property
and consider following the pattern you see here.

Potrebbero piacerti anche