UsingCsla4 03 DataAccess
UsingCsla4 03 DataAccess
UsingCsla4 03 DataAccess
Data Access
Rockford Lhotka
Using CSLA .NET 4: Data Access
All rights reserved. No part of this work may be reproduced or transmitted in any form or by any
means, electronic or mechanical, including photocopying, recording, or by any information
storage or retrieval system, without the prior written permission of the copyright owner.
Trademarked names may appear in this book. Rather than use a trademark symbol with every
occurrence of a trademarked name, we use the names only in an editorial fashion and to the
benefit of the trademark owner, with no intention of infringement of the trademark.
The information in this book is distributed on an “as is” basis, without warranty. Although every
precaution has been taken in the preparation of this work, the author shall not have any liability
to any person or entity with respect to any loss or damage caused or alleged to be caused directly
or indirectly by the information contained in this work.
The source code for this book (CSLA 4 version 4.1.0) is available at
http://www.lhotka.net/cslanet.
Revision: 1.0
Acknowledgements
Neither this book, nor CSLA 4, would have
been possible without support from Magenic.
Magenic is the premier .NET development
company in the US, and is a Microsoft Gold
Certified Partner.
Separating Concerns
When thinking about object persistence, there are three broad areas of functionality that should be
considered. Each area has its own concerns and responsibilities that should be kept as separate as
possible. Figure 3 illustrates these areas of concern.
Encapsulated Models
Two of the four models encapsulate the data functionality within the business classes. The data
access code itself may be in an external data access component, or it may be implemented directly
within the business class.
Either way, the basic structure of a business class is consistent. This example shows the code
necessary to implement a Fetch operation:
[Serializable]
public class PersonEdit : BusinessBase<PersonEdit>
{
public static void GetPersonEdit(int id, EventHandler<DataPortalResult<PersonEdit>> callback)
{
DataPortal.BeginFetch<PersonEdit>(id, callback);
}
#if !SILVERLIGHT
public static PersonEdit GetPersonEdit(int id)
{
return DataPortal.Fetch<PersonEdit>(id);
}
The asynchronous and synchronous factory methods invoke the client-side data portal to initiate
the Fetch operation. The client-side data portal uses convention and configuration to determine
how to communicate with the server-side data portal. Remember that the “server-side” data portal
will be running on the physical client machine in a 1- or 2-tier deployment.
The server-side data portal creates an instance of the business class and invokes the
DataPortal_Fetch method, passing the criteria value provided by the factory method into the
DataPortal_Fetch method.
Using CSLA 4: Data Access Page 5
Rev 1.0
You can implement DataPortal_Fetch to interact with an external data access component; a
model called encapsulated invocation. Or, you can implement the data access code directly in the
DataPortal_Fetch method; a model called encapsulated implementation.
Notice that the method is public, and that it accepts a CompletedHandler parameter that must
be invoked when the method is complete. It is also a void method, because all results are returned
through the callback handler.
It is critical that the callback parameter be invoked when the method is complete,
whether an exception occurs or not. If the callback parameter isn’t invoked, the data
portal won’t know that the method has completed. The application will be stuck
thinking the data access operation is still running.
If the code in the DataPortal_XYZ method does invoke an asynchronous service or other
asynchronous operation, the callback handler should not be invoked until the asynchronous
operation is complete.
I often use the EditorBrowsable attribute from the System.ComponentModel namespace to
“hide” the method from Intellisense. Ideally this method would be non-public because it should
never be called except by the data portal. Unfortunately, due to limitations on reflection and
dynamic method invocation in Silverlight and WP7, the method must be public. The
EditorBrowsable attribute helps minimize the impact by hiding the method from developers using
the business type.
Using CSLA 4: Data Access Page 6
Rev 1.0
Factory Models
Two of the four models require implementation of a factory object that manages the data access
interaction for the business type. The data access code itself may be in the factory class, or it may
be in an external data access component invoked by the code in the factory class.
Either way, the basic structure of the business and factory classes are consistent. This example
shows the code for a business class using a factory model:
[Serializable]
[ObjectFactory("MyApp.DataAccess.PersonFactory,MyApp.DataAccess")]
public class PersonEdit : BusinessBase<PersonEdit>
{
public static void GetPersonEdit(int id, EventHandler<DataPortalResult<PersonEdit>> callback)
{
DataPortal.BeginFetch<PersonEdit>(id, callback);
}
#if !SILVERLIGHT
public static PersonEdit GetPersonEdit(int id)
{
return DataPortal.Fetch<PersonEdit>(id);
}
#endif
}
The ObjectFactory attribute on the business class tells the data portal to create and use a
factory object to manage the data access interaction for this business type. The attribute requires
that a factory name be supplied. By default, this name is the assembly qualified name of the factory
type. You can create a custom factory loader that interpets this value in any way you choose.
The asynchronous and synchronous factory methods invoke the client-side data portal to initiate
the Fetch operation. The client-side data portal uses convention and configuration to determine
how to communicate with the server-side data portal. Remember that the “server-side” data portal
will be running on the physical client machine in a 1- or 2-tier deployment.
Notice that there’s no DataPortal_Fetch method in the business class. When using a factory
model, there are no DataPortal_XYZ methods in the business class. All data access related code is
in a separate factory class. The server-side data portal creates an instance of the factory class and
invokes a Fetch method on the factory object, passing the criteria value provided by business
class’s static factory method into the Fetch method.
This example shows a factory class that supports the Fetch operation for the PersonEdit
business class:
public class PersonFactory : ObjectFactory
{
public PersonEdit Fetch(int id)
{
var result = new PersonEdit();
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
MarkOld(result);
return result;
}
}
In a factory model, the factory is responsible for several steps, including the following:
Although there’s no requirement that a factory class inherit from the ObjectFactory base class,
this base class does provide protected methods that make it easier to implement a factory class.
The callback handler is invoked to tell the data portal when the method is complete, and that is
how the result is returned to the data portal.
It is critical that the callback handler be invoked whether an exception occurs or not.
If the callback handler isn’t invoked the data portal will not know that the method
has completed.
If the code does invoke an asynchronous service or behavior, the callback handler should be
invoked when the asynchronous operation is complete.
Metastate Management
I’ll discuss managing state and metastate in detail later in this chapter. You should be aware that
the two object factory models do require that you manage all business objects’ metastates
manually, whereas the other two models allow the data portal to manage the metastate
automatically.
Automatic management of metastate helps reduce common bugs and results in simpler code.
Manual metastate management allows for broad flexibility in the DAL implementation. So the
choice is really one of simplicity vs flexibility.
Encapsulated Invocation
In this model the server-side data portal component creates an instance of the business class and
invokes a DataPortal_XYZ method on that object. The business object is responsible for invoking
the DAL.
Figure 4 illustrates the process flow for this model.
Factory Implementation
With the factory implementation model, the server-side data portal component creates an instance
of a factory object based on the information provided by an ObjectFactory attribute on the
business class. This factory object is responsible for the following:
Factory Invocation
In the factory invocation model, the server-side data portal component creates an instance of a
factory object based on the information provided by an ObjectFactory attribute on the business
class. This factory object is responsible for the following:
Encapsulated Implementation
In the encapsulated implementation model, the DAL functionality is implemented directly in the
DataPortal_XYZ methods in the business classes. This model involves the simplest code, but at the
expense of any flexibility or clear separation between the business code and data access code.
Figure 7 illustrates the process flow for this model.
The goal should be complete isolation of data access technologies (including ORM
tools) within the Data Access layer so all other layers of the application are
independent and unaware of the data access technology in use.
Using CSLA 4: Data Access Page 15
Rev 1.0
Managing State
Well designed business objects exist because they have a responsibility or purpose within the
context of a use case or user scenario. Most objects require some data to implement the behaviors
necessary to fulfill that responsibility. This data is called the state of the object.
I view the behavior of an object as being the most important part of the object, and
any state contained in the object is only present to meet the needs of those
behaviors.
Most object state is persisted as the object is retrieved or saved. Some object state might be
calculated or derived from other state, or by interacting with other business objects; and that state
is usually not persisted.
Some application data exists completely in the database, at least from the perspective of any
specific user scenario. One example might be a user scenario where the user edits some customer
information. The objects represent behaviors around finding and selecting the customer to edit,
and then retrieving, editing, validating, and saving the customer data.
But at the Data Storage layer, there might be triggers or stored procedures that automatically
create audit log information to record which user retrieved and saved the customer data. This audit
information is probably critical application data, but may have no representation in the business
objects for this user scenario because that data has no relevance to the user.
You need to try to ensure that your business objects only contain the minimum state necessary
to implement the behaviors the object needs to fulfill its responsibility. That state is what will be
persisted by the Data Access layer as the object is retrieved or saved.
It is important to understand that persisting state is a bi-directional process. When you fetch an
object, that object’s state is loaded by the Data Access layer from the Data Storage layer. When you
save an object, that object’s state is inserted, updated, or deleted in the Data Storage layer. That
process will often affect the state of the object as well.
For example, when you insert a new row into a database, the database often creates a new
primary key and a new timestamp value for that row. Both of those values are usually part of the
object’s state. Similarly, when you update an existing row in a database, the database often creates
a new timestamp value for that row, and this timestamp value is part of the object’s state.
This means that even the operation of saving an object’s state will usually alter the object’s state
as part of the process.
As I discuss each persistence operation and how those operations are supported by the data
portal you will see this bi-directional requirement has on object persistence.
Concurrency
Concurrency is often necessary to protect data integrity in multi-user applications. There are three
basic types of concurrency:
3. Pessemistic
Pessemistic concurrency generally requires “locking” of data in the database so only one user
can interact with the data at any given time. Today’s highly distributed applications, and modern
data access technologies don’t generally support pessimistic concurrency, and so I won’t discuss it
here.
Optimistic concurrency doesn’t “lock” any data. Instead, it relies on the application to determine
whether changes to the database can be overwritten by other concurrent users of the application.
The default behavior of an application that doesn’t implement concurrency is optimistic, last
write wins. If multiple users edit the same data and then save their edits, each subsequent user’s
save will overwrite any previously saved values. This means that the edits made by the last user to
save are the only edits preserved in the database.
You can choose to implement optimistic, first write wins. In this case, the first user to save will
have their edits persisted in the database. All subsequent concurrent users will be unable to save,
typically getting an exception indicating that they are attempting to overwrite someone else’s
changes to the data.
The most common way to implement this type of concurrency is to use a timestamp column in
each table of the database. This timestamp value is updated any time a record is inserted or
updated into the database.
When the application retrieves data from the database table, it also retrieves the timestamp
value. Before saving the data the database ensures that the timestamp of the data in memory
matches the timestamp on the table. If the timestamp values match the database knows that the
data in the database hasn’t already been changed. On the other hand, if the timestamp values don’t
match, the database will raise an error to indicate a concurrency violation.
In the context of a CSLA .NET application, the timestamp value or values from the database must
be maintained as properties in the business object graph. These are usually private properties,
because they provide no value to the user interface or other business logic. These properties exist
for the purpose of storing the timestamp value between the time the data is retrieved from the
database and when an update operation is attempted to change the values in the database.
Transactions
Most database update operations are protected by a database transaction. Within .NET there are
four major transactional technologies:
ADO.NET transactions
Database-level transactions
TransactionScope from the System.Transactions namespace
Enterprise Services (COM+) distributed transactions
AutoCloneOnUpdate Feature
The challenge is that persistence is bi-directional. So as the state of each object in the graph is saved
into the database, that object was probably changed to reflect any database-generated key or
timestamp values. Although the database will roll back to a consistent state if there’s a failure, the
objects in memory could be left in an indeterminate state where they contain data that no longer
matches what’s in the database.
The data portal includes functionality to prevent this from being a problem: the
AutoCloneOnUpdate feature. Before the data portal invokes your Data Access layer code, it takes a
snapshot of the object graph. In the case of failure, the database transaction first rolles back all
changes to the database. Then, the data portal reverts the object graph to this snapshot. This
ensures that all objects in the graph are also in a known state.
Disabling AutoCloneOnUpdate
There is some overhead to taking this snapshot, and it is possible to disable this feature of the data
portal. You might disable this feature if you encounter performance issues due to the feature, and if
you are able to implement an alternative solution to the problem.
The most common alternative solution is to entirely discard the object graph and to reload it
from the database. This solution also incurs a great deal of overhead, and results in the user losing
any changes they’ve made to the state of the objects in the graph.
Another common alternative is to entirely discard the object graph and to throw an exception.
This solution avoids the overhead, but leaves the user with no object graph and typically just some
error dialog on their screen.
If you do want to disable the feature you need to add an entry to your app.config or
web.config file in the appSettings region:
<appSettings>
<add key="CslaAutoCloneOnUpdate" value="False"/>
</appSettings>
This will disable the feature for all objects in your application.
I will demonstrate the use of transactions later in this book as I walk through the various ways
you can implement a Data Access layer.
Using CSLA 4: Data Access Page 18
Rev 1.0
Managing Metastate
In the Using CSLA 4: Creating Business Objects ebook, I discussed the idea of object metastate, and
how CSLA .NET business objects maintain and use various metastate values such as:
IsNew
IsDirty
IsSelfDirty
IsDeleted
IsValid
IsSelfValid
IsSavable
IsBusy
IsSelfBusy
As objects are retrieved and saved during the persistence process, these metastate values must
be correctly updated. The data portal can be used in two different modes, one of which will
automatically manage the metastate on your behalf, and the other of which you must manually
update the values.
The primary metastate values that must be maintained during object persistence are listed in
Table 2.
Value Description
IsNew This value should be true when there is reasonable expectation that the
primary identifier of the object doesn’t correspond to any row or element in
the data store; it should be false if there’s a reasonable expection that the
object corresponds to a row or element in the data store
IsSelfDirty This value should be true if there is a reasonable expectation that one or
more state values don’t match their corresponding values in the data store;
it will also be true if the IsDeleted metastate property has been set to true
IsDeleted This value is set to true to indicate that data corresponding to the object
should be deleted from the data store during an Update persistence
operation
The MarkNew method must be called as an object is created. This method results in IsNew and
IsSelfDirty being true, and IsDeleted being false.
The MarkNew method is also called after an object has been deleted during an update operation.
At first glance, this may seem strange, but once an object has been deleted it meets the definition
of a new object because the object’s state no longer corresponds to data in the data store.
Using CSLA 4: Data Access Page 19
Rev 1.0
The MarkOld method must be called after an object has been updated (inserted or deleted into
the data store). This method results in IsNew, IsSelfDirty, and IsDeleted being false.
The MarkDeleted method is called on a root object to mark that object for deletion. This sets the
IsDeleted property to true. The IsDeleted property of child objects is set to true by the parent
object, never directly on the child object. Typically, this occurs when a child object is removed from
a parent BusinessListBase object.
If you are implementing a parent object that directly contains a child object (without an
intervening collection), your parent object will use the DeleteChild method defined on the
IEditableBusinessObject interface in the Csla.Core namespace. The BusinessBase class
implements this interface, so all editable child objects can be cast to the IEditableBusinessObject
type.
Again, whether you need to manually worry about these details depends on which data portal
model you choose to utilize in your application. I will show you examples of each model later in this
book.
SQL Server
SQL Azure
Windows Azure Storage
Oracle
MySQL
DB2
SOAP services
REST services
XML files
Delimited text files
Isolated storage
Mainframes or other legacy systems
If you can write .NET code to interact with your data store, you should be able to use
that technology to persist your business object state.
SOAP services
REST services
Isolated storage
If your Silverlight or WP7 application needs to access other data sources, you should either use
the data portal in a 3- or 4-tier deployment, or call remote SOAP or REST services that provide
access to the required data.
You might also use third party ORM tools, data access tools, or abstractions over raw ADO.NET
such as the Enterprise Library’s Data Access Application Block (from Microsoft’s Patterns and
Practices group).
CSLA .NET doesn’t dictate which technology you use to interact with your relational databases.
My recommendation is to use either raw ADO.NET or the ADO.NET Entity Framework.
You should realize that raw ADO.NET is the basis for every other data access technology. Every
other data access technology is built on top of raw ADO.NET. If you are looking for the highest
performance, “closest to the metal” option then you should choose raw ADO.NET. Everything else is
just a layer of abstraction over this core technology.
Microsoft has made it clear that their current strategic data access technology choice is ADO.NET
Entity Framework (EF). This technology is an abstraction layer over raw ADO.NET that provides
object-relational mapping (ORM) features and may allow you to author simpler code for database
interaction than the code you’d write with raw ADO.NET.
The TableAdapter and DataSet technology has been part of .NET from the beginning, but it
hasn’t carried forward into newer platforms like Silverlight and WP7. Other newer technologies
such as WCF Data Services are built on top of EF and don’t work well with the DataSet. In general
my recommendation is to avoid building new code using the TableAdapter/DataSet model.
LINQ to SQL is a competitor to EF, and it also provides basic ORM functionality. As I mentioned
earlier, Microsoft has made it clear that their current strategic data access technology choice is EF.
For this reason, my recommendation is to avoid building new code using LINQ to SQL.
In general, you should use WCF to call remote services. Microsoft has made it clear that their
strategic technology direction for service authoring and invocation is WCF.
Older .NET applications would add a web service reference to SOAP services, allowing Visual
Studio to generate a web service client proxy using the web services technology. Although you can
still use this technology, you can accomplish the same thing using the more modern WCF
technology by adding a service reference to your project.
There may be times when it is simpler to call some non-SOAP services manually through the
WebRequest or WebClient types in .NET. This is a lower level and less abstract technology than WCF
or web service client proxies, and can give you more control over how your code interacts with the
remote service.
You should not use object serialization to persist object data in files.
You should resist this temptation. These serializers are all version sensitive. If you serialize an
object graph to a file, then update the application with new assemblies (including changing your
business types), you may be unable to deserialize the data from the file back into objects. At that
point, you’ve lost the data.
Using CSLA 4: Data Access Page 22
Rev 1.0
Instead, you should treat isolated storage files like any other data storage technology. Any data
should be persisted into these files through a formal data access layer.
Persistence Operations
Data persistence is often described using the CRUD acronym, standing for:
Create
Read
Update
Delete
It should be clear how these translate to object persistence, in that objects must be created,
fetched (read), updated, and deleted.
Those operations address all the requirements of editable and read-only object stereotypes.
CSLA .NET also supports object stereotypes that represent pure action, such as the Command and
Using CSLA 4: Data Access Page 23
Rev 1.0
Unit of Work stereotypes. To support these stereotypes, the data portal also implements an
Execute operation.
As you read through the following discussion of each operation, remember that child objects are
always persisted as part of their top-level root object. Many data portal operations apply only to
root objects, and it is the responsibility of that root object to persist its child objects. Some data
portal operations exist to help root objects as they implement persistence for their child objects.
Create
The Create operation is used to create new instances of business types. It is important to formally
support the concept of object creation, because some objects must be initialized with template
data from the database as they are created.
For example, when creating a new CustomerEdit object for a specific sales person, the new
object might be initialized with the sales person’s information, including their id, region, and other
relevant information.
This information will often come from the database, and you can think of a Create operation as
being very much like a Fetch operation, except that the object is loaded with template data instead
of existing object data.
Sometimes you won’t need to initialize a new object with data, and the data portal supports this
requirement as well.
Table 3 lists the data portal methods that support this operation.
Method Description
Create Synchronously creates and initializes a new root object
BeginCreate Asynchronously creates and initializes a new root object
CreateChild Synchronously creates and initializes a new child object; only available when
using one of the encapsulated data portal models (see Table 1)
Once the business object has been created and initialized, it is returned to the calling code for
use by the application.
The Create and BeginCreate methods accept zero or one criteria parameter that is used to
provide information to the server-side DAL code about how the object should be initialized. If you
need to pass multiple criteria values you need to create a type based on the Criteria object
stereotype as described in Using CSLA 4: Creating Business Objects.
Fetch
The Fetch operation is used to retrieve instances of business types that are populated with data
from the data store.
Table 4 lists the data portal methods that support this operation.
Method Description
Fetch Synchronously retrieves and loads a existing root object
BeginFetch Asynchronously retrieves and loads a existing root object
FetchChild Synchronously retrieves and loads a child object; only available when using
one of the encapsulated data portal models (see Table 1)
Once the business object has been loaded with data it is returned to the calling code for use by
the application.
The Fetch and BeginFetch methods accept zero or one criteria parameters that is used to
provide information to the server-side DAL code so it can find the appropriate data to use when
loading the business object’s state. If you need to pass multiple criteria values, you need to create a
type based on the Criteria object stereotype as described in Using CSLA 4: Creating Business
Objects.
Using CSLA 4: Data Access Page 25
Rev 1.0
Update
The Update operation is the most complex operation, because it can result in different actions
depending on the metastate values of the business objects in the object graph. These actions are:
Insert
Update
Delete
When using one of the encapsulated data portal models (see Table 1), the Update operation
examines the metastate of the business object to determine which action to perform. If you are
using one of the factory data portal models, your factory object code is responsible for examining
the metastate and taking the correct action. Table 5 lists the rules that should be applied. Not all
metastate combinations are possible, so only valid combinations are listed.
Method Description
Update Synchronously inserts, updates, or deletes a root object
BeginUpdate Asynchronously inserts, updates, or deletes a root object
UpdateChild Synchronously inserts, updates, or deletes a child object; only available
when using one of the encapsulated data portal models (see Table 1)
As you can see, these are rules that should be checked before an object is saved. This is why you
should prefer to use the Save and BeginSave methods instead of the Update and BeginUpdate
methods from the data portal.
The Save and BeginSave methods are virtual, so if you need to add extra rules or behaviors as
part of the save process you can override these methods.
The Csla.Core namespace also defines an ISavable interface that includes Save and BeginSave
methods. You can use this interface to implement polymorphic code that can save any editable root
object, regardless of whether it is a single object or a list. Table 8 lists the members defined by the
ISavable interface.
Method Description
Save Synchronously inserts, updates, or deletes a root object by invoking the data
portal
BeginSave Asynchronously inserts, updates, or deletes a root object by invoking the
data portal
Saved Event raised when an object has been saved
Failure to update references to use the object returned from Save or BeginSave is a
common cause of bugs in application code.
Here’s an example showing how to properly call the Save method on an editable object:
_person = _person.Save();
And here’s an example showing how to properly call the BeginSave method on an editable
object:
_person.BeginSave((o, e) =>
{
if (e.Error != null)
throw e.Error;
else
_person = (PersonEdit)e.NewObject;
});
In both cases, notice that the original _person field is updated to use the new object returned as
a result of the save operation. The code handling the asynchronous callback must also check for,
and rethrow or handle, any exceptions that occurred during the async operation.
Most applications will be using data binding to connect the business object to the UI, and that
data binding reference must also be updated. I’ll demonstrate how to update these references in
the UI technologies covered by subsequent books in this ebook series.
The important thing to understand is that all references to the original object must be updated
to use the new object returned from the save operation. Failure to update these references will
cause undesirable results in your application.
ForceUpdate Option
The Save method defined on all editable root objects, and by the ISavable interface, has an
overload that accepts a Boolean parameter named forceUpdate. This overload exists to support a
specific web-based scenario where a web application or service is designed to support a completely
stateless web server.
I will demonstrate the use of the forceUpdate parameter in the Using CSLA 4: ASP.NET MVC
ebook.
Normally, when you call the Save method on an object; the object’s state is inserted or updated
into the database depending on the value of the object’s IsNew property. If the forceUpdate
parameter is true, the data portal will ignore the IsNew property of the business object and will
always perform an update (instead of an insert) action. For example:
var person = PersonEdit.NewPersonEdit();
person.Id = id;
person.FirstName = firstName;
person.LastName = lastName;
person = person.Save(true);
Using CSLA 4: Data Access Page 28
Rev 1.0
The PersonEdit object created will be new (IsNew is true). The object is then loaded with data,
including the object’s Id property (representing its primary key in the database). When the Save
method is called, the forceUpdate parameter is passed as true, so the data portal operates as
though IsNew were false. Instead of an insert action, this results in an update action.
This behavior is necessary in the case where a web postback or service call comes into the web
server that contains all the data from an existing business object. If the server is completely
stateless, it must recreate that existing business object with the data provided in the postback or
service call. When an object is created like this, its IsNew property will be true, even though the
object already exists. The forceUpdate option allows the application to force the data portal to
perform an update instead of an insert action.
The Update operation is the most complex operation because the result is an insert, update, or
delete action. Additionally, editable root objects know how to “save themselves” through their Save
and BeginSave methods. These methods invoke the Update or BeginUpdate methods on the data
portal, so normal business code won’t ever call Update or BeginUpdate directly.
Delete
The Delete operation is used to delete data related to an editable root business object.
Table 9 lists the data portal methods that support this operation.
Method Description
Delete Synchronously deletes data corresponding to a root object
BeginDelete Asynchronously deletes data corresponding to a root object
Nothing is returned as a result of a Delete operation. The operation either works, or results in an
exception to indicate failure.
Execute
The Execute operation is used to execute arbitrary server-side code that is encapsulated within a
business object. Normally the Execute operation is applied to business objects that inherit from the
CommandBase class.
Table 10 lists the data portal methods that support this operation.
Method Description
Execute Synchronously executes server-side code associated with a command object
BeginExecute Asynchronously executes server-side code associated with a command
object
Table 10. Data portal methods that support the Execute operation
The Execute and BeginExecute methods are found on the client-side DataPortal type. The data
portal routes the request to the server-side data portal component, and that component invokes
your business object or factory object depending on the data portal model you are using. The
server-side code can then implement arbitrary behaviors that run on the server. That server-side
code might interact with the DAL, or any other resources available on the server.
Here are examples of synchronous and asynchronous command object factory methods using
the data portal:
#if !SILVERLIGHT
public static OrderShipper ShipOrder(int orderId)
{
var cmd = new OrderShipper(orderId);
return DataPortal.Execute<OrderShipper>(cmd);
}
#endif
Each model offers different benefits, but I am covering them in order from most to least
recommended, with a focus on the encapsulated invocation and factory implementation models.
See the discussion in Chapter 1 for more background information.
Before I provide examples of each of the data portal models, I will discuss some concepts that
are common to all four models. This includes; authorizing data portal requests, handling
transactions, and the basic structure of the DataPortal_XYZ methods and factory methods.
RunLocal Attribute
In .NET, the decision to run data access invocation code locally is made when implementing the
data access invocation method: the DataPortal_XYZ method or the ObjectFactory method.
For example, the following DataPortal_Create method will run locally:
[RunLocal]
protected override void DataPortal_Create()
{
using (BypassPropertyChecks)
{
Id = -1;
}
base.DataPortal_Create();
}
This method initializes the business object’s Id property with a hard-coded value.There’s no
reason for this method to run on an application server. The RunLocal attribute tells the data portal
that this method should run locally.
ProxyMode Parameter
In Silverlight and WP7, the decision to run data access invocation code locally is made in the static
factory method of the business class. Most Silverlight applications involve a 3- or 4-tier deployment,
Using CSLA 4: Data Access Page 33
Rev 1.0
where the data access invocation methods exist only on the server, not on the client. If CSLA .NET
required the use of a RunLocal attribute on Silverlight, you would be required to deploy the data
access code to the client, and that is undesirable.
The client-side data portal methods for Silverlight and WP7 accept an optional ProxyMode
parameter that can be used to force the data portal to run code locally. For example, the following
factory method forces the object creation to run locally:
public static void NewPersonEdit(EventHandler<DataPortalResult<PersonEdit>> callback)
{
DataPortal.BeginCreate<PersonEdit>(callback, DataPortal.ProxyModes.LocalOnly);
}
Like the BeginCreate method, all the Silverlight data portal methods have an overload that
accepts a ProxyMode parameter. If this value is LocalOnly, then the data portal will run the “server-
side” code locally on the client workstation or device.
Static Events
The client-side data portal defines a set of events that are raised on each data portal invocation.
These events can be used to detect when a data portal method call starts, when the call is
underway, and when the call is complete.
These events are static, and so it is important to use them carefully to avoid memory leaks.
Remember that setting up an event handler creates a reference from the event source to the
handler. When an event source is a static event, that reference will never go away unless the
event handler is explicitly unhooked from the event.
DataPortalInitInvoke Event
The DataPortalInitInvoke event is raised by the client-side data portal at the very beginning of
each data portal method call.
You can handle this event to perform any initialization of the ClientContext or GlobalContext
dictionaries in Csla.ApplicationContext. The data portal passes these dictionaries to the
application server on each data portal call, and this event is raised before those dictionaries are
serialized by the data portal.
DataPortalInvoke Event
The DataPortalInvoke event is raised by the client-side data portal immediately before the server-
side data portal is invoked.
You can handle this event to be notified when each server-side call is being made. The event
arguments contain information about the data portal method call, including the data portal
operation being performed and either the business object type or the business object itself.
The primary purpose for this event is to implement logging and instrumentation for the
application. For example, you might write code in the event handler to record a Windows event for
the data portal call so the Windows Event Viewer can be used to monitor the number of times the
data portal calls the server.
Application Context
CSLA .NET includes an ApplicationContext type in the Csla namespace. The ApplicationContext
type is used to provide global access to various application context values, including:
The ApplicationContext type is available to application code in any logical layer, and it often
contains properties or values that are useful to the Interface Control, Business, and Data Access
layers.
Although this is generally reliable, you will find that WPF sets this value to null in many cases,
rendering the user’s identity unavailable.
Code running in ASP.NET can also access this value through the current HttpContext object:
System.Security.Principal.IPrincipal user = HttpContext.Current.User;
In fact, the only reliable way to access the user’s principal in ASP.NET is through the current
HttpContext object.
The Silverlight and WP7 runtimes define the IPrincipal interface, but don’t provide any global
location to store or access the value. There’s no real concept of a “current user” built into Silverlight
or WP7.
The purpose of the User property on the Csla.ApplicationContext type is to provide a
consistent way for you to write code that uses the current user’s principal and identity information.
Table 11 lists where the User property gets its value depending on the runtime environment.
I will discuss user authentication in the Using CSLA 4: Data Portal Configuration ebook, but it is
important to understand that you have two basic choices for authentication: Windows Active
Directory and custom authentication.
Windows Impersonation
If you are using Windows Active Directory authentication you are relying on the Windows operation
system to authenticate the user and to manage the user’s principal and identity. This includes
impersonation when making data portal calls from the client to the server.
I’ll discuss how to configure the data portal for Windows impersonation in Chapter 5 and in the
Using CSLA 4: Data Portal Configuration ebook. When using Windows impersonation, the data
portal doesn’t copy the client-side user principal to the server. There is no need, because the
Windows operating system and network stack do that work.
Custom Impersonation
The default data portal behavior is to assume you are using custom authentication. This means your
application is not relying on the Windows operating system to authenticate the user. Instead, the
application has authenticated the user through the ASP.NET MembershipProvider model, with
ASP.NET forms authentication, or with custom code.
The result is that the user’s principal object is a serialiable implementation of the IPrincipal
interface from the System.Security.Principal namespace. I’ll discuss this and related concepts in
detail in the Using CSLA 4: Data Portal Configuration ebook.
When using custom authentication the server-side data portal will copy the client-side principal
object to the server with each data portal call. This is done to provide a consistent experience
where your authorization rules run against the same user identity on the client and server.
Manual Impersonation
Sometimes the principal object can be quite large. Custom principal and identity objects may
contain many roles (in a List<string>), or a lot of user profile information. If these objects contain
a lot of data, the process of serializing them to the server with each data portal call can become a
performance issue.
If you encounter this issue when using custom authentication you can implement manual
impersonation. In this approach you recreate the user’s principal and identity objects from the
database or other data store on each data portal request. There’s a performance cost to recreating
these objects on each request, but sometimes this cost is lower than the cost of transferring the
data over the network with each request.
I’ll discuss the specific implementation of this approach in the Using CSLA 4: Data Portal
Configuration ebook. At a high level it involves the following steps:
1. Configure the data portal for Windows authentication (thereby preventing it from serializing
the principal to the server on each call)
Using CSLA 4: Data Access Page 37
Rev 1.0
2. Put the username or other user id value into the ClientContext dictionary of
Csla.ApplicationContext so it becomes available to the server
3. Implement a custom IAuthorizeDataPortal provider and recreate the user’s principal and
identity objects in the Authorize method
In my experience, most applications don’t need to take this approach, but if your principal or
identity objects contain large amounts of data this technique can be valuable.
ExecutionLocation Property
The ExecutionLocation property indicates the physical location where the code is currently
executing: Silverlight, Client, or Server. These locations are listed in Table 12.
Value Description
Silverlight Indicates the code is running on a Silverlight or WP7 client workstation or device
Client Indicates the code is running on a Windows client workstation, or on the web
server in an ASP.NET Web Forms or MVC application
Server Indicates the code is running on an application server when the data portal is
configured for a 3- or 4-tier deployment
LogicalExecutionLocation Property
The LogicalExecutionLocation property indicates the logical execution location for the code.
Several times in this book I’ve mentioned that “server-side” code will run on the client workstation
Using CSLA 4: Data Access Page 38
Rev 1.0
or web server when the application is deployed in a 1- or 2-tier scenario. In that case, the
ExecutionLocation property will always return Silverlight or Client, but the
LogicalExecutionLocation will return Client or Server depending in the logical location of the
code.
For example, in a WPF application deployed in a 2-tier scenario all the application’s code will run
on the client workstation. The ExecutionLocation property will always return Client, even when
“server-side” code is running.
In that same example, the LogicalExecutionLocation property will return Client or Server
depending on whether the current code is logically “client-side” or “server-side”.
LocalContext
The ApplicationContext type has a LocalContext property. This property is a dictionary of values
available to the application.
The LocalContext dictionary is maintained on a per-thread basis for all code outside ASP.NET,
and is maintained in the current HttpContext inside ASP.NET. This means that the values in
LocalContext are global to the application, but isolated to the current thread or HttpContext.
CSLA .NET uses the LocalContext dictionary to store certain short-term values that should be
available within a specific thread or HttpContext, and you can use LocalContext to store your own
values as well.
For code running on a smart client (WPF or Silverlight for example), LocalContext is a place to
store values that should be global to all code on the client. The dictionary remains in memory
throughout the life of the application.
For code running on a web or application server, LocalContext only exists for the duration of
the current server request. As each request ends, the dictionary is removed from memory.
ClientContext
The ApplicationContext type has a ClientContext property. This property is a dictionary of values
that is maintained by client-side code, but is also made available to server-side code. The data
portal copies the ClientContext dictionary from the client to the server with every data portal
request.
Like the LocalContext value, ClientContext is maintained on the current thread or
HttpContext. Also, it is maintained in memory for the entire life of the application on a smart client
(WPF or WP7 for example), and is lost at the end of each server request when running in a server
environment such as ASP.NET.
Be very careful what you put into ClientContext, because all values and objects in
ClientContext are serialized from the client to the server on every data portal
request. Putting large amounts of data in ClientContext can cause performance
problems.
CSLA .NET does not store any values in ClientContext, and the data portal has optimizations to
minimize overhead when making server requests if ClientContext is entirely unused.
Using CSLA 4: Data Access Page 39
Rev 1.0
The ClientContext dictionary is a good location to store small application configuration and
context values that should be available to code on the client and server. For example, some
applications are used by many divisions or departments within an organization. As the application
starts up the current corporate department may be loaded into ClientContext so it is available to
all application code on client and server. This value may be used by business and authorization rules
or other aspects of the application.
GlobalContext
The ApplicationContext type has a GlobalContext property. This property is a dictionary of values
that is maintained by code on both the client and server. The data portal serializes GlobalContext
from the client to the server, and then back to the client, on every data portal request.
As with the other context dictionaries, this one is maintained on the current thread or
HttpContext, is available for the life of a smart client application, and is lost at the end of each
server request when running in a server environment such as ASP.NET.
Be extremely careful when putting values into GlobalContext. These values are
serialized from client to server and back to the client on every data portal request.
Putting values in GlobalContext can cause performance problems.
CSLA .NET does not store any values in GlobalContext, and the data portal has optimizations to
minimize overhead when making server requests if GlobalContext is entirely unused.
The GlobalContext dictionary is a good location to put limited debugging or trace information
during development and testing. I recommend avoiding its use in most production settings to avoid
possible performance problems.
IAuthorizeDataPortal Interface
Every time the server-side data portal is invoked it invokes an authorizer that implements the
IAuthorizeDataPortal interface from the Csla.Server namespace. The default implementation
allows all data portal calls to succeed.
You can create your own implementation of the IAuthorizeDataPortal interface to create more
restrictive authorization for the data portal. The interface requires that the class implement an
Authorize method:
protected class NullAuthorizer : IAuthorizeDataPortal
{
public void Authorize(AuthorizeRequest clientRequest)
{
// implement authorization here and
// throw exception to deny call
}
}
Using CSLA 4: Data Access Page 40
Rev 1.0
This method is invoked immediately after the client request has been deserialized. The order of
events for each data portal request is as follows:
3. Client request data is deserialized into objects (except for Silverlight and WP7 clients)
5. Client request data is deserialized into objects (Silverlight and WP7 clients only)
6. The ClientContext and GlobalContext values are loaded into the server-side
ApplicationContext type
As you can see, when the Authorize method is invoked the data portal has deserialized the
client request into objects, the ApplicationContext dictionaries are loaded, and the current user
principal has been set to an appropriate value.
This means the code you write in the Authorize method can make use of all context and user
identity information, as well as the information provided through the AuthorizeRequest
parameter. Table 13 lists the values provided through that parameter.
Member Description
ObjectType Gets the type of business object affected by the client request
RequestObject Gets a reference to the criteria or business object passed from the client to the
server
Operation Gets a DataPortalOperations value indicating the data portal operation
requested by the client; one of: Create, Fetch, Update, Delete, Execute
However, the primary reason for implementing this interface is to determine whether to allow
each data portal request to be processed by the server. If you do not want a request to be
processed your Authorize method implementation should throw an exception. This exception will
be returned to the caller to indicate the reason the request was not processed by the server.
MobileFactory Attribute
When building a Silverlight or WP7 application you may choose to use a 4-tier deployment as shown
in Figure 8.
The MobileFactory attribute accepts a string parameter that is used to identify the type of the
mobile factory object that should run on the web server. By default, this parameter is interpreted as
the assembly qualified name of the mobile factory class. Nevertheless, you can implement a mobile
factory loader that interprets the value any way you choose.
A mobile factory class must implement public methods that are invoked by the data portal:
Create, Fetch, Update, and Delete. Only methods appropriate to the business object stereotype
are required. For example, a read-only business object would only require a Fetch method in the
factory class. Here’s an example of a mobile factory class that implements a Fetch method:
public class PersonFactory
{
public PersonEdit Fetch(int id)
{
// verify that this operation should be allowed here
return DataPortal.Fetch<PersonEdit>(id);
}
}
A mobile factory class is implemented exactly like a data factory class, but its purpose is
different. Instead of implementing or invoking data access code, a mobile factory verifies that the
requested operation should be allowed, or invokes the business rules on objects being updated.
At this point, you should understand how data portal requests come into the server and are
authorized. You’ve also seen how the data portal copies certain bits of client-side data to the server
to provide location transparency for the application’s code.
I’ll now move on to discuss the next step in the server-side data portal processing: optionally
enlisting the operation in a transaction.
Database Transactions
The server-side data portal invokes your DataPortal_XYZ or object factory methods to perform
Create, Fetch, Update, or Delete operations. By default, these methods are invoked without any
pre-existing transactional context, but you can use the Transactional attribute to tell the data
portal to enlist in a transaction before invoking these methods.
Transactional Attribute
The Transactional attribute is in the Csla namespace, and it is applied to the DataPortal_XYZ
methods of a root object, or to the methods in an object factory. If this method is applied to any
other methods it will have no affect on those methods or the data portal.
Manual
TransactionScope
EnterpriseServices
Manual Transactions
The data portal defaults to using Manual transactions. In this case the code you write in the
DataPortal_XYZ or object factory method is responsible for enlisting in its own transaction using
whatever technology you choose.
The most common scenario is to use ADO.NET transaction objects such as a SqlTransaction
from the System.Data.SqlClient namespace. For example:
protected override void DataPortal_Insert()
{
using (var cn = new SqlConnection())
{
cn.Open();
using (var tr = cn.BeginTransaction())
{
// invoke access layer here
tr.Commit();
}
}
}
This code explicitly creates a SqlTransaction object using the BeginTransaction method of the
SqlConnection object. And the transaction is explicitly committed once the data access code is
complete.
Any exception encountered during the data access process will prevent the Commit method from
being called and the transaction will automatically roll back. Additionally, the data portal expects
that any failure during data access will result in an exception, so there’s no effort to catch any
exceptions in this code.
In Chapter 3 I will discuss some helper types in the Csla.Data namespace that make it easier to
implement manual transactions for object graphs that contain parent-child relationships.
You can use any transactional technology you choose when implementing manual transactions.
This includes ADO.NET transactions as shown in this example, TransactionScope transactions, or
database-level transactions.
The TransactionScope parameter passed to the Transactional attribute tells the data portal to
enlist in a TransactionScope before invoking this DataPortal_Insert method. The same idea
applies to methods in an object factory class. For example:
[Transactional(TransactionalTypes.TransactionScope)]
public PersonEdit Update(PersonEdit obj)
{
// implement data access here
return obj;
}
In both models the idea is the same: by the time your code is invoked the data portal has already
created a TransactionScope object so your code is running in a transactional context.
Notice that this code is much simpler. Any interaction with the database is automatically
protected by a transaction. If no exception is thrown during the data access process the transaction
will automatically commit when your method is complete.
Any exception will cause the data portal to roll back the transaction and perform normal failure
processing, including returning the exception to the client-side code.
The TransactionScope created by the data portal uses default values for all settings, including
the isolation level and timeout value. This means the transaction is Required, has an isolation level
of Serializable, and has a one minute timeout. If you need different values from the defaults, you
will need to use manual transactions and create your own TransactionScope object.
It is also important to understand that the TransactionScope object will automatically use the
Microsoft Distributed Transaction Coordinator (DTC) if more than one database connection is
opened during the data access processing. It doesn’t matter if these connections are open at the
same time, or one after another. If more than one connection is opened the DTC is enlisted.
The reason this is important is that the DTC incurs substantial performance overhead.
Additionally, the DTC is not enabled on most client workstations by default. If the data access code
is running on a client workstation, the code will throw an exception when it fails to locate the DTC.
Most parent-child object models will open more than one connection during data access and so
this is a common issue. In Chapter 3 I will discuss several helper types in the Csla.Data namespace
that are designed to simplify the process of reusing a single database connection for all data access
actions across an entire object graph.
As with the TransactionScope option, the data portal enlists the code in a transaction before
invoking your method. If the data access code completes without throwing an exception, the
transaction is automatically commited. If an exception is thrown, the transaction is rolled back.
Because Enterprise Services transactions always use the DTC, they always incur the performance
penalty associated with a distributed transaction. On the other hand, these transactions protect
access to multiple databases, and support more types of database than the TransactionScope
object provides.
Transactions are an important part of any data access model, and the data portal provides
simplicity through TransactionScope and EnterpriseServices, or flexibility through Manual
transactions.
The data portal may throw other exceptions as well. Specifically, if the data portal was unable to
reach the server due to network errors or similar issues, you should expect to catch exceptions
specific to the network technology you are using. The most common source of these exceptions will
be WCF (System.ServiceModel) or other components from the System.Net namespace.
The reason the data portal throws exceptions of type DataPortalException, is that the
exception contains useful information about the original exception that would otherwise be lost or
unavailable. Table 14 lists the properties available from the DataPortalException type (beyond
those normally available from the base Exception type).
Property Description
BusinessException Gets the original server-side exception that was thrown, bypassing all
intermediate exceptions that may have been inserted by the data portal
BusinessObject Gets a reference to the business object as it was on the server at the time of the
exception
StackTrace Gets the full stack trace for the exception, including the client-side and server-side
stack traces merged into one unified stack trace
The consolidated stack trace property is valuable for debugging, because it includes the entire
history of the exception from the point that it was thrown on the server, through any intermediate
steps on the server and client, right up to where the exception was caught on the client.
The BusinessObject property can also be useful for debugging, because it provides a reference
to the business object as it was at the time of the exception. In many cases, this business object will
be in an indeterminate state, because its properties and metastate will have been partially altered
during the data access process, but the changes were never completed due to the exception.
Property Description
ExceptionTypeName Type name of the original exception object
Message Message text from the exception
Source Source property value from the exception
StackTrace Stack trace text derived from the exception
TargetSiteName TargetSiteName value from the exception
InnerError WcfErrorInfo object containing the exception information from the
InnerException property of the original exception
Exception Inspector
When an exception is thrown by code in the DataPortal_XYZ or object factory method, it is
returned to the client. Before the data portal serializes the exception on the server, you can
“rewrite” the exception. This can be useful in cases where you want to globally change one
exception type into another before the exception is returned to the client.
Notice that the original exception is included as the InnerException value of the new exception.
This avoids losing any detail about the exception, while still rewriting the top-level exception that is
returned to the client.
In the web.config file on the server (or app.config for a 1- or 2-tier deployment) you need to
tell the data portal to use this inspector by supplying an assembly-qualified type name:
<appSettings>
<add key="CslaDataPortalExceptionInspector"
value="Library.Inspector,Library"/>
</appSettings>
The assembly containing this type must be deployed to the machine that is running the “server-
side” data portal components.
Encapsulation Models
When using the data portal with one of the encapsulation models the data portal calls methods on
the root business object, and those methods are responsible for invoking or implementing the data
access code.
DataPortal_Create Method
The DataPortal_Create method is invoked by the data portal when a new root obect is being
created. The data portal creates a new instance of the root business type, the object’s MarkNew
method is invoked, and then the DataPortal_Create method is invoked to initialize the object with
appropriate data.
That Create method is provided with an int parameter, and so the data portal will invoke an
overload of the DataPortal_Create method that accepts an int parameter:
private void DataPortal_Create(int regionId)
{
using (BypassPropertyChecks)
{
// initialize object here
}
base.DataPortal_Create();
}
The data portal follows normal .NET rules for invoking overloaded methods. If a
DataPortal_Create method can’t be found with a parameter type that matches the parameter
from the Create or BeginCreate method an exception is thrown.
In this example I show how to call the base implementation. This is a good practice if you want
the default behavior of running the business rules for the object after the object’s data has been
initialized.
Also notice that the object initialization occurs within a using block for the object’s
BypassPropertyChecks property. This ensures that business and authorization rules aren’t run as
properties are set with new values.
Here’s an example of a Silverlight implementation of the DataPortal_Create method:
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public void DataPortal_Create(
int id, Csla.DataPortalClient.LocalProxy<PersonEdit>.CompletedHandler handler)
{
try
{
// invoke external DAL here (encapsulated invoke)
// or implement DAL code here (encapsulated implementation)
handler(this, null);
}
catch (Exception ex)
{
handler(null, ex);
The assumption is that a DataPortal_XYZ method running on the Silverlight or WP7 client will
invoke a remote SOAP or REST service. Because all server interactions must be async on Silverlight,
the code inside this DataPortal_Create method will be async. Given those assumptions, the
DataPortal_Create method accepts a callback handler parameter that must be invoked when the
method is complete. That is true whether there’s an exception or not, so the implementation or
invocation code is wrapped in a try..catch block.
The EditorBrowsable attribute blocks this method from appearing in Intellisense. The method
must be public due to limitations on reflection and dynamic method invocation in Silverlight, but
the method should never be called directly. Hiding it from Intellisense is a good practice because it
reduces the chance that a developer will accidentally think they should be able to call this method.
DataPortal_Fetch Method
The DataPortal_Fetch method is invoked by the data portal when the Fetch or BeginFetch data
portal method is invoked. The data portal creates an instance of the root business type, calls the
object’s MarkOld method, and then calls the DataPortal_Fetch method. This method is responsible
for invoking or implementing the data access code necessary to load the object with existing data
from the data store.
You must implement a DataPortal_Fetch method that accepts the same criteria parameter type
as the criteria value provided to the Fetch or BeginFetch method. On Silverlight and WP7 the
DataPortal_Fetch must also accept an async callback parameter.
It will cause the data portal to invoke the following DataPortal_Fetch method:
private void DataPortal_Fetch(int id)
{
// get data from DAL
using (BypassPropertyChecks)
{
// load object properties
}
}
The data portal follows normal .NET rules for invoking overloaded methods. If a
DataPortal_Fetch method can’t be found with a parameter type that matches the parameter from
the Fetch or BeginFetch method an exception is thrown.
Also notice that the object initialization occurs within a using block for the object’s
BypassPropertyChecks property. This ensures that business and authorization rules aren’t run, as
properties are set with new values. If you set properties without this step, the object will be marked
as having changes even though it was just fetched, and that will result in unexpected behaviors
within the object and most user interfaces.
Here’s an example of a Silverlight implementation of the DataPortal_Fetch method:
Using CSLA 4: Data Access Page 51
Rev 1.0
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public void DataPortal_Fetch(
int id, Csla.DataPortalClient.LocalProxy<PersonEdit>.CompletedHandler handler)
{
try
{
// invoke external DAL here (encapsulated invoke)
// or implement DAL code here (encapsulated implementation)
handler(this, null);
}
catch (Exception ex)
{
handler(null, ex);
}
}
DataPortal_Insert Method
The DataPortal_Insert method is invoked by the data portal when an editable root object is saved
using its Save or BeginSave method. This only occurs if the object’s IsNew property is true and its
IsDeleted property is false. After the DataPortal_Insert method completes, the data portal will
call the object’s MarkOld method.
On .NET the DataPortal_Insert method accepts no parameters. On Silverlight and WP7 the
method must define and invoke an async callback handler parameter. Here’s an example of a .NET
implementation:
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Insert()
{
using (BypassPropertyChecks)
{
// invoke external DAL here (encapsulated invoke)
// or implement DAL code here (encapsulated implementation)
}
}
DataPortal_Update Method
The DataPortal_Update method is invoked by the data portal when an editable root object is saved
using its Save or BeginSave method. This only occurs if the object’s IsNew property is false and its
IsDeleted property is false. After the DataPortal_Update method completes, the data portal will
call the object’s MarkOld method.
On .NET the DataPortal_Update method accepts no parameters. On Silverlight and WP7 the
method must define and invoke an async callback handler parameter. Here’s an example of a .NET
implementation:
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Update()
{
using (BypassPropertyChecks)
{
// invoke external DAL here (encapsulated invoke)
// or implement DAL code here (encapsulated implementation)
}
}
DataPortal_DeleteSelf Method
The DataPortal_DeleteSelf method is invoked by the data portal when an editable root object is
saved using its Save or BeginSave method. This only occurs if the object’s IsNew property is false
and its IsDeleted property is true.
After the DataPortal_DeleteSelf method completes, the data portal will call the object’s
MarkNew method. This may seem strange, but once the object’s data has been deleted there is a
reasonable expectation that the object does not correspond to any existing data in the database.
That is the definition of a new object, so it makes sense that IsNew and IsDirty should now be
true.
Using CSLA 4: Data Access Page 53
Rev 1.0
On .NET the DataPortal_DeleteSelf method accepts no parameters. On Silverlight and WP7
the method must define and invoke an async callback handler parameter. Here’s an example of a
.NET implementation:
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_DeleteSelf()
{
using (BypassPropertyChecks)
{
// invoke external DAL here (encapsulated invoke)
// or implement DAL code here (encapsulated implementation)
}
}
DataPortal_Delete Method
The DataPortal_Delete method is invoked by the data portal when the Delete or BeginDelete
data portal method is invoked. The data portal creates an instance of the root business type and
then calls the DataPortal_Delete method. This method is responsible for invoking or implementing
the data access code necessary to remove the object’s data from the data store.
You must implement a DataPortal_Delete method that accepts the same criteria parameter
type as the criteria value provided to the Delete or BeginDelete method. On Silverlight and WP7
the DataPortal_Delete must also accept an async callback parameter.
For example, consider the following factory method:
public static void DeletePersonEdit(int id)
{
return DataPortal.Delete<PersonEdit>(id);
}
It will cause the data portal to invoke the following DataPortal_Delete method:
private void DataPortal_Delete(int id)
{
// invoke external DAL here (encapsulated invoke)
// or implement DAL code here (encapsulated implementation)
}
Using CSLA 4: Data Access Page 54
Rev 1.0
The data portal follows normal .NET rules for invoking overloaded methods. If a
DataPortal_Delete method can’t be found with a parameter type that matches the parameter
from the Delete or BeginDelete method an exception is thrown.
Here’s an example of a Silverlight implementation of the DataPortal_Delete method:
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public void DataPortal_Delete(
int id, Csla.DataPortalClient.LocalProxy<PersonEdit>.CompletedHandler handler)
{
try
{
// invoke external DAL here (encapsulated invoke)
// or implement DAL code here (encapsulated implementation)
handler(this, null);
}
catch (Exception ex)
{
handler(null, ex);
}
}
DataPortal_OnDataPortalInvoke Method
The DataPortal_OnDataPortalInvoke method is called by the server-side data portal before the
appropriate DataPortal_XYZ method is invoked. You can think of this as a pre-processing method
where you can run code before every data portal invocation.
The standard base classes for object stereotypes all contain a virtual implementation of this
method that you can override if you want to implement pre-processing behaviors. The most
common reason for overriding this method is to implement logging or tracing code for
instrumentation or diagnostics in your application.
This method is synchronous on both .NET and Silverlight, and looks like this:
protected override void DataPortal_OnDataPortalInvoke(DataPortalEventArgs e)
{
// implement your behavior here
base.DataPortal_OnDataPortalInvoke(e);
}
The DataPortalEventArgs parameter provides useful information about the current data portal
request. The members of this type are listed in Table 16.
Member Description
Operation A DataPortalOperations value indicating the type of data portal operation
being performed (Create, Fetch, Update, Delete, or Execute)
ObjectType The type of the business object being processed by the data portal
Exception Any exception that occurred during the DataPortal_XYZ method
DataPortal_OnDataPortalInvokeComplete Method
The DataPortal_OnDataPortalInvokeComplete method is invoked by the server-side data portal
after a DataPortal_XYZ method has successfully completed. You can think of this method as a post-
processing method where you can write code that should run after every successful data portal
operation.
This method is synchronous on both .NET and Silverlight and looks like this:
protected override void DataPortal_OnDataPortalInvokeComplete(DataPortalEventArgs e)
{
// implement your behavior here
base.DataPortal_OnDataPortalInvokeComplete(e);
}
The primary purpose for overriding this method is to implement instrumentation or diagnostic
code for your application.
As with the previous method, this one accepts a DataPortalEventArgs parameter that contains
an Operation property indicating the reason for the current data portal request.
DataPortal_OnDataPortalException Method
The DataPortal_OnDataPortalException method is invoked by the server-side data portal after a
DataPortal_XYZ method has thrown an exception. You can think of this method as a post-
processing exception handler where you can write code that should run after every unsuccessful
data portal operation.
This method is synchronous on both .NET and Silverlight and looks like this:
protected override void Child_OnDataPortalException(DataPortalEventArgs e, Exception ex)
{
// implement your behavior here
base.Child_OnDataPortalException(e, ex);
}
The primary purpose for overriding this method is to implement instrumentation or diagnostic
code for your application.
As with the previous two methods, this one accepts a DataPortalEventArgs parameter that
contains Operation and Exception properties you can use in your code.
Remember that you can also rewrite the exception before it is returned to the client by providing
your own IDataPortalExceptionInspector implementation. I discussed this earlier in the chapter.
You should understand that the DataPortal_OnDataPortalException method is invoked before
any custom IDataPortalExceptionInspector implementation.
Factory Models
When using the data portal with one of the factory models, the data portal calls methods on a
factory object that is associated with a business type. The methods implemented in the factory class
are responsible for implementing or invoking the data access code.
ObjectFactory Attribute
The data portal must be provided with information about the factory type associated with each
business type. This is done through the ObjectFactory attribute. For example:
[Csla.Server.ObjectFactory("DataAccess.Mock.PersonDal,DataAccess.Mock")]
[Serializable]
public class PersonEdit : BusinessBase<PersonEdit>
The ObjectFactory attribute is applied to a root business class. It requires a string parameter
that provides the name of the factory type. By default this string contains the assembly qualified
name of the type.
You can override that behavior by implementing your own custom factory type loader that
interprets the string value in any way you choose. This means that any time you use a factory
model you automatically have the ability to create a pluggable data access layer.
When the server-side data portal detects the ObjectFactory attribute on a root business type, it
will create an instance of the factory type and then invoke data operation methods on that factory
object.
By default, the names of the data operation methods are those listed in Table 17.
Name Description
Create Implements the create operation
Fetch Implements the Fetch operation
Update Implements the update operation (insert, update, and delete actions)
Delete Implements the delete operation
Execute Implements the execute operation
Invoke Implements any pre-processing behaviors
InvokeComplete Implements any post-processing behaviors
InvokeException Implements any post-processing exception behaviors
In that case the data portal will invoke methods on the factory object based on the alternate
method names you’ve provided.
IObjectFactoryLoader Interface
As I discussed earlier, the ObjectFactory attribute requires a string parameter that provides the
name of the factory type associated with the root business type. By default this value is interpreted
as the assembly qualified type name of the factory class.
The interpretation of the parameter value is handled by an object called an object factory loader.
You can provide your own object factory loader to interpret the parameter value in any way you
choose. This is done by implementing the IObjectFactoryLoader interface and then configuring
the server-side data portal to use your factory loader instead of the default implementation.
Here’s an example of a factory loader that emulates the default behavior:
public class FactoryLoader : Csla.Server.IObjectFactoryLoader
{
public object GetFactory(string factoryName)
{
return Activator.CreateInstance(GetFactoryType(factoryName));
}
The interface requires that the factory loader implement a GetFactoryType method that returns
a Type object based on the factoryName parameter provided to the ObjectFactory attribute. You
can interpret the parameter value in any way you choose. For example, you might do one of the
following:
The factory loader must also implement a GetFactory method that returns an instance of the
factory type. The simplest implementation is the one shown above, where the .NET Activator type
is used to create an instance of the type. You may also perform any initialization of the factory
object in this method.
Here’s an example of a factory loader that creates a type name by combining a configuration
value with the factoryName parameter:
public class FactoryLoader : Csla.Server.IObjectFactoryLoader
{
public string Assembly { get; set; }
public FactoryLoader()
{
The ObjectFactory attribute should now provide only the name of the factory class, not the
assembly. For example:
[Csla.Server.ObjectFactory("PersonDal")]
The config file will contain entries to tell the data portal to use this custom factory loader, and
for the ObjectFactoryAssembly value:
<appSettings>
<add key="ObjectFactoryAssembly" value="DataAccess.Mock"/>
<add key="CslaObjectFactoryLoader" value="DataAccess.FactoryLoader,DataAccess"/>
</appSettings>
The CslaObjectFactoryLoader config value provides the data portal with the assembly qualified
type name of the custom factory loader implementation. That factory loader then reads the
ObjectFactoryAssembly config value to get the assembly and namespace that should be used to
create the assembly qualified type names of each factory class.
ObjectFactory Class
An object factory class is nothing more than a class that implements public methods for the
required data operations. For example:
public PersonList Fetch()
{
var result = new PersonList();
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
// load result with data
return result;
}
Like most Fetch and Create methods, this example method creates an instance of the business
type and returns it as a result.
The challenge with implementing this Fetch method is that the factory object needs to have
some way of manipulating the state and metastate of the business object. The PersonList type is a
Member Description
LoadProperty Loads a property value without invoking authorization or business rules
ReadProperty Reads a property value without invoking authorization rules
MarkAsChild Invokes MarkAsChild on the target object (editable object only)
MarkNew Invokes MarkNew on the target object (editable object only)
MarkOld Invokes MarkOld on the target object (editable object only)
BypassPropertyChecks Gets the BypassPropertyChecks object from the target object (editable
object only)
CheckRules Invokes the CheckRules method on the target object’s BusinessRules
object (editable object only)
FieldExists Gets a value indicating whether a managed backing value already exists for
the target property
GetDeletedList Gets the DeletedList collection from a BusinessListBase or
BusinessBindingListBase object
SetIsReadOnly Sets the IsReadOnly property on a ReadOnlyListBase,
ReadOnlyBindingListBase, or NameValueListBase object
At this point you should understand how factory objects are created by the data portal, and how
you can use the ObjectFactory base class to implement factory types. I’ll now discuss each data
operation method you may implement in factory types.
Create Method
The Create method is invoked by the data portal when a new root obect is being created. The data
portal creates a new instance of the factory type and then the Create method is invoked.
The Create method is responsible for the following:
Notice that I’m using the phrase “business object graph”, because the Create method may
create one object, or an entire object graph with a root object.
Here’s an example of a synchronous Create method on .NET:
public PersonEdit Create()
{
var result = new PersonEdit();
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
MarkNew(result);
CheckRules(result);
return result;
}
You can see how this method performs each step, starting with creating an instance of the
business object and ending with returning that object as a result.
Because this Create method doesn’t accept a parameter, it corresponds to this data portal
Create method call:
public static PersonEdit NewPersonEdit()
{
return DataPortal.Create<PersonEdit>();
}
The data portal uses standard .NET method overloading rules. If the data portal’s Create or
BeginCreate method is passed a criteria value, the data portal will invoke a Create method in the
factory object that accepts a parameter of that type. This is the same behavior I described earlier
for the DataPortal_XYZ methods.
This Create method is not invoked asynchronously by the data portal, but the data portal
assumes the code inside this method will be asynchronous. When using a local data portal
configuration on a Silverlight client, the assumption is that the factory method will invoke a remote
SOAP or REST service. Because all server calls must be asynchronous on Silverlight, the
implementation of any factory method is assumed to contain asynchronous code.
The important thing to understand is that the Create method you implement in a factory class is
entirely responsible for creating, initializing, and returning the requested business object or object
graph. This includes initializing the new object’s state and metastate.
Fetch Method
The Fetch method is invoked by the data portal when an existing root obect is being retrieved. The
data portal creates a new instance of the factory type and then the Fetch method is invoked.
The Fetch method is responsible for the following:
The process is very similar to the Create method, except the Fetch method loads the object or
object graph with existing data. Here’s an example of a synchronous Fetch method on .NET:
public PersonEdit Fetch(int id)
{
var result = new PersonEdit();
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
MarkOld(result);
return result;
}
The data portal uses standard .NET method overloading rules. If the data portal’s Fetch or
BeginFetch method is passed a criteria value, the data portal will invoke a Fetch method in the
factory object that accepts a parameter of that type. This is the same behavior I described earlier
for the DataPortal_XYZ methods.
When factory classes are implemented to run on Silverlight and WP7 the methods are
asynchronous and so they must accept a callback handler parameter. For example:
public void Fetch(
Csla.DataPortalClient.LocalProxy<PersonEdit>.CompletedHandler handler)
{
try
{
var result = new PersonList();
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
MarkOld(result);
handler(result, null);
}
catch (Exception ex)
{
handler(null, ex);
}
}
As with the Create method, it is important to understand that the Fetch method you implement
in a factory class is entirely responsible for creating, loading, and returning the requested business
object or object graph. This includes initializing the new object’s state and metastate.
Update Method
The Update method is invoked by the data portal when an editable root object is saved. This
method handles the insert, update, and delete actions, and so it is the most complex of the factory
methods.
The Update method accepts the root business object as a parameter, and returns the root
business object as a result. In most cases the same object is returned as a result, but it is possible
for an Update method to entirely reload or recreate the object graph if appropriate.
Here’s an example of a synchronous Update method on .NET:
public PersonEdit Update(PersonEdit obj)
{
if (obj.IsDeleted)
{
if (!obj.IsNew)
using (BypassPropertyChecks(obj))
{
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
}
MarkNew(obj);
}
Using CSLA 4: Data Access Page 63
Rev 1.0
else if (obj.IsNew)
{
using (BypassPropertyChecks(obj))
{
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
}
MarkOld(obj);
}
else
{
using (BypassPropertyChecks(obj))
{
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
}
MarkOld(obj);
}
return obj;
}
Notice how the implementation uses the root object’s metastate to determine if the object is
marked for deletion, or is new. If IsDeleted is true, the object’s data is deleted. If IsNew is true,
the object’s data is inserted. Otherwise, the object’s data is updated.
In each case, the object’s metastate is updated appropriately. For example, once an object’s data
has been deleted, the object is marked as new by calling the MarkNew method from the
ObjectFactory base class.
If the root object contains child objects, the Update method is responsible for inserting,
updating, or deleting those objects as well. I typically use private methods in the factory class to
implement those actions for each type of object in an object graph.
The same requirements apply to an asynchronous Update method on Silverlight or WP7:
public void Update(
PersonEdit obj, Csla.DataPortalClient.LocalProxy<PersonEdit>.CompletedHandler handler)
{
try
{
if (obj.IsDeleted)
{
if (!obj.IsNew)
using (BypassPropertyChecks(obj))
{
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
}
MarkNew(obj);
}
else if (obj.IsNew)
{
using (BypassPropertyChecks(obj))
{
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
}
MarkOld(obj);
}
else
{
using (BypassPropertyChecks(obj))
{
// implement DAL code here (factory implementation)
This Update method is not invoked asynchronously by the data portal, but the data portal
assumes the code inside this method will be asynchronous. When using a local data portal
configuration on a Silverlight client, the assumption is that the factory method will invoke a remote
SOAP or REST service. Because all server calls must be asynchronous on Silverlight, the
implementation of any factory method is assumed to contain asynchronous code.
Delete Method
The Delete method is invoked by the data portal when an immediate delete operation is required.
Like the Create and Fetch methods, the Delete method can accept a criteria parameter to identify
the data to be deleted.
Here’s an example of a synchronous Delete method on .NET:
public void Delete(int id)
{
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
}
This method is invoked by the data portal in response to a Delete or BeginDelete method call
like this:
public static void DeletePersonEdit(int id)
{
DataPortal.Delete<PersonEdit>(id);
}
Notice how the parameter type of the data portal Delete call matches the parameter accepted
by the Delete method in the factory class.
Here’s an example of an asynchronous Delete method on Silverlight:
public void Delete(
int id, Csla.DataPortalClient.LocalProxy<PersonEdit>.CompletedHandler handler)
{
try
{
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
handler(null, null);
}
catch (Exception ex)
{
handler(null, ex);
}
}
The callback handler parameter is required so the Delete method can tell the data portal when
the operation is complete.
Using CSLA 4: Data Access Page 65
Rev 1.0
Execute Method
The Execute method is invoked by the data portal when a command object is executed. The data
portal passes the root business object to the Execute method, and expects the root object to be
returned as a result.
Here’s an example of a synchronous Execute method on .NET:
public OrderShipper Execute(OrderShipper obj)
{
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
return obj;
}
The Execute method can interact with the properties of the command object, and will often
implement or invoke data access code to perform the requested action. As with all command
objects, it is important to realize that a command doesn’t always correspond to a direct data access
operation. The code in this Execute method can interact with any server-side resources, other
business objects, and the database.
Here’s an example of an asynchronous Execute method on Silverlight or WP7:
public void Execute(
OrderShipper obj, Csla.DataPortalClient.LocalProxy<OrderShipper>.CompletedHandler handler)
{
try
{
// implement DAL code here (factory implementation)
// or invoke external DAL here (factory invoke)
handler(obj, null);
}
catch (Exception ex)
{
handler(null, ex);
}
}
As with the other asynchronous factory methods, the assumption is that the code inside this
method will invoke remote SOAP or REST services, or will execute code on a background thread.
While the Execute method isn’t invoked asynchronously by the data portal, the data portal expects
that the method will implement asynchronous behaviors.
At this point, you should understand the factory methods that implement the Create, Fetch,
Update, Delete, and Execute data portal operations. The data portal also invokes methods for pre-
and post-processing of data portal operations.
Invoke Method
A factory class on .NET can implement an Invoke method. This method is invoked by the server-side
data portal before any method implementating a data portal operation. You can think of the Invoke
method as being a place to implement pre-processing code that should run before any data
operation.
This feature doesn’t exist on Silverlight or WP7, and any Invoke method you implement in a
client-side factory class won’t be invoked by the data portal.
InvokeComplete Method
A factory class on .NET can implement an InvokeComplete method. This method is invoked by the
server-side data portal after every successful data portal operation. You can think of the
InvokeComplete method as being a place to implement post-processing code that should run after
any data operation.
This feature doesn’t exist on Silverlight or WP7, and any InvokeComplete method you implement
in a client-side factory class won’t be invoked by the data portal.
The most common reason for implementing this method is for logging, instrumentation, or
diagostics. This method is invoked after the data portal operation is complete, and before results
are serialized back to the client.
Here’s an example of the InvokeComplete method:
public void InvokeComplete(Csla.Server.DataPortalContext context)
{
// implement post-processing here
}
InvokeError Method
A factory class on .NET can implement an InvokeError method. This method is invoked by the
server-side data portal after any data portal operation that throws an exception.
This feature doesn’t exist on Silverlight or WP7, and any InvokeError method you implement in
a client-side factory class won’t be invoked by the data portal.
The most common reason for implementing this method is for logging, instrumentation, or
diagostics. This method is invoked after the data portal operation is complete, when the operation
has thrown an exception.
Here’s an example of the InvokeError method:
public void InvokeError(Exception ex)
{
// implement exception handling here
}
The Exception object is passed to the method as a parameter, so you can log or record the
exception information.
Csla.Data Namespace
Table 19 provides a summary of the types from the Csla.Data namespace I will discuss in this
chapter.
Type Description
ConnectionManager Enables reuse of a single IDbConnection database connection object
ObjectContextManager Enables reuse of a single ADO.NET Entity Framework context object
TransactionManager Enables reuse of a single IDbConnection database connection object
and associated IDbTransaction ADO.NET transaction object
ContextManager Enables reuse of a single LINQ to SQL context object
DataMapper Copies property and field values from one object to another using
dynamic property or field invocation
ObjectAdapter Converts data from an object into a DataSet or DataTable
SafeDataReader Provides an IDataReader data reader implementation that
automatically replaces all null data values with empty or zero
equivalents
This example uses the ConnectionManager type to get access to an open SqlCeConnection
object. If no database connection already existed, one is created and opened. But if a database
connection was already open, that open connection is reused.
Looking at this code, you can’t tell if the GetManager method created and opened a connection,
or just returned access to an already open connection. That is the point of this coding pattern; to
abstract this behavior out of your code and into the framework.
The most important part of this coding pattern is that the data access code for every object
performs all object persistence within the using block for the manager object. That must include
any method calls to persist child objects, or other root objects.
A connection manager object detects when the any data access code enters the first using
block, and it creates and opens the appropriate database connection, object context, or other
managed data object. That connection object is held open until that first using block exits.
Using CSLA 4: Data Access Page 70
Rev 1.0
This is illustrated in Figure 9, where you can see how multiple levels of using blocks are nested
within the top-level using block created by the first object.
ConnectionManager Class
The ConnectionManager class is designed to enable the reuse of standard ADO.NET connection
objects. There are two requirements on the connection class:
1. The connection class must implement IDbConnection from the System.Data namespace
2. The connection class must implement a public constructor that accepts the database
connection string as a parameter
All standard database connection objects meet these requirements, including SqlConnection for
SQL Server databases and SqlCeConnection for SQL Server Compact Edition databases.
Here is an example of a typical using block with a ConnectionManager type:
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
// interact with database using ctx.Connection
}
The GetManager method has several overloads with parameters as described in Table 20.
The first GetManager method call opens or reuses the connection associated with the default
label. The second GetManager method call opens or reuses the connection associated with the
MyLabel label.
The ConnectionManager type doesn’t alter the way database connection objects work. It simply
provides a way to reuse an already-open connection. This means that any code you use that
interacts with the connection object must follow the normal rules for that type of connection
object.
The GetManager has the same overloads as for the ConnectionManager type, as described in
Table 20.
The ObjectContextManager type doesn’t alter the way EF context objects work. It provides a
way to reuse an existing context object and its already-open database connection. Any standard EF
context object can be used with the ObjectContextManager type.
TransactionManager Class
The TransactionManager type is designed to enable the reuse of an ADO.NET transaction object.
This type should be used with Manual data portal transactions, where you are creating and using
your own database transaction through ADO.NET.
The TransactionManager type works with any transaction type that implements the
IDbTransaction interface from the System.Data namespace. This includes all transaction types
from standard ADO.NET database implementations, including those for SQL Server and other major
databases.
Here’s an example of using the TransactionManager type:
using (var ctx = TransactionManager<SqlCeConnection, SqlCeTransaction>.GetManager("LocalDb"))
{
// access the transaction with ctx.Transaction
// interact with database using ctx.Connection
}
The GetManager method opens or reuses an existing database connection and transaction
object.
If the outermost using block exits without an exception, the transaction is committed and the
database connection is closed.
If the outermost using block exits due to an unhandled exception, the transaction is rolled back
and the database connection is closed.
The GetManager method accepts the same parameters as with the ConnectionManager type, as
described in Table 20.
Within the using block, you can access the database connection through the manager’s
Connection property.
Using CSLA 4: Data Access Page 73
Rev 1.0
You can also access the transaction object through the manager’s Transaction object.
Remember that the TransactionManager type will automatically call the Commit and Rollback
metods on the transaction object. You should not invoke those methods manually.
ContextManager Class
The ContextManager type is designed to enable the reuse of LINQ to SQL context object. A LINQ to
SQL context object contains an open database connection, along with managing the state of data
objects associated with the context.
When using LINQ to SQL to build data access code, you will need to reuse the same open context
object to avoid opening multiple database connections, and to ensure that LINQ to SQL is able to
consistently persist all related data objects.
Here’s an example of using the ContextManager type:
using (var ctx = ContextManager<LocalDbContext>.GetManager("LocalDb"))
{
// ctx.Context is the LINQ to SQL context object
}
The GetManager has the same overloads as for the ConnectionManager type, as described in
Table 20.
The ContextManager type doesn’t alter the way LINQ to SQL context objects work. It simply
provides a way to reuse an existing context object and its already-open database connection. Any
standard LINQ to SQL context object can be used with the ContextManager type.
At this point, you should understand the value of the connection and context manager types,
and how they enable the abstract reuse of already-open database connections within your data
access code.
DataMapper Class
When Web Forms data binding needs to insert or update data, it provides the data elements to the
ASP.NET data source control in the form of a dictionary object of name/value pairs. The
CslaDataSource control from the Csla.Web assembly and namespace provides this dictionary
object to the UI code as an event argument.
This means that in a typical Web Forms application that uses the CslaDataSource, the UI code
must copy the values from the dictionary to the business object’s properties. The name is the name
of the property to be updated, and the value is the value to be placed into the property of the
business object. Copying the values isn’t hard—the code looks something like this:
cust.FirstName = e.Values["FirstName"].ToString();
cust.LastName = e.Values["LastName"].ToString();
cust.City = e.Values["City"].ToString();
Code implementing a service in WCF or the older asmx technology has a similar scenario, where
the values passed to the service as part of the XML or JSON message are translated into a set of
data objects. The data values from those objects must be copied into the business object’s
properties. Again, the code isn’t difficult to write:
Unfortunately, this is tedious code to write and debug; and if your object has a lot of properties,
this can add up to a lot of lines of code. An alternative is to use reflection or the dynamic setting of
property values to automate the process of copying the values.
The DataMapper class uses reflection and dynamic property setting technology to help automate
these data mapping operations; from either a collection implementing IDictionary or an object
with public properties.
In any case, it is possible or even likely that some properties can’t be mapped. Business objects
often have read-only properties, and obviously it isn’t possible to set those values. Yet the
IDictionary or DTO may have a value for that property. It is up to the business developer to deal
on a case-by-case basis with properties that can’t be automatically mapped.
The DataMapper class will accept a list of property names to be ignored. Properties matching
those names simply won’t be mapped during the process. Additionally, DataMapper will accept a
Boolean flag that can be used to suppress exceptions during the mapping process. This can be used
simply to ignore any failures.
An alternative is to provide DataMapper with a DataMap object that explicitly describes the source
and target properties for the mapping.
Map Method
The most basic use of the DataMapper class involves the Map method. This method maps data values
from a source object to a target object. It does not loop over collections or traverse object graphs.
The Map method copies property values from one object to another.
DataMapper.Map(source, target);
object
IDictionary
object
Dictionary<string, object>
Table 21 describes how each mapping occurs by default (without the use of an explicit DataMap
object).
Mapping Description
object, object Properties from the source are mapped to properties of exactly the
same name and type on the target
IDictionary, object Elements from the dictionary are mapped to properties of the target
object, where the target property names exactly match the key names
in the dictionary
object, Dictionary Properties from the source are mapped to entries of the target, using
the source property names as keys in the dictionary
Non-Browsable Properties
The System.ComponentModel namespace includes a Browsable attribute. This attribute is used by
.NET to indicate properties that are not available for data binding.
The Map method is a sort of “data binding”, in that it binds data values from one object to
another. Because of this, any source object properties that are decorated with the
Browsable(false) attribute are ignored during the mapping process. This includes the metastate
properties on editable business objects such as IsNew and IsDeleted.
Using an IgnoreList
The Map method has numerous overloads to support the mappings listed in Table 21. It is also
possible to provide an ignore list parameter that tells the Map method to ignore certain properties
from the source object.
During the mapping process, properties in this list are simply ignored, whereas all other property
values are copied. You can use this feature to avoid trying to map values into a read-only property,
or getting values the user isn’t authorized to read.
The DataMap constructor requires that the types of the source and target objects be provided.
This is required, because reflection is used behind the scenes to get PropertyInfo or FieldInfo
objects for each property or field you specify. X lists the methods used to load a DataMap with
mappings.
Method Description
AddPropertyMapping Sets up a mapping from one property to another property
AddFieldMapping Sets up a mapping from one field to another field (even if the fields are
non-public)
AddFieldToPropertyMapping Sets up a mapping from a field to a property
AddPropertyToFieldMapping Sets up a mapping from a property to a field
The Map method works the same as described earlier, except that it uses the information in the
DataMap object to determine the source and target properties or fields. Because you are specifying
the map explicitly, no ignoreList parameter is used.
Value Coersion
In cases where the source and target property or field types don’t match, the Map method will
attempt to coerce the source value into the target type. The coercion used is aggressive, and will
Using CSLA 4: Data Access Page 77
Rev 1.0
attempt to use every technique available in .NET to cast or convert the source value to the target
type.
The value coercion is implemented by the CoerceValue method from the Csla.Utilities class.
The CoerceValue method is public, and can be used by your code directly if you find it of value.
This method uses a number of techniques in an attempt to coerce a value to the new type,
including:
It is important to understand that this coercion process is automatically invoked by the Map
method when the source and target property or field types don’t match. You may find that values
from a source object successfully map to the target in cases where a simple cast would fail, and that
is because this coercion process is more aggressive than a simple cast operation.
The DataMapper type can be useful in simplifying or reducing repetitive code for mapping data
from one object to another. It is designed to support Web Forms and service development, but you
can use it any time data must be mapped from one object to another.
ObjectAdapter Class
The ObjectAdapter class is similar to the DataMapper class, in that it is designed to map data from
business objects into a DataSet or DataTable object.
The ObjectAdapter class implements a Fill method. This method works much like the Fill
method from a standard ADO.NET TableAdapter object. The Fill method copies property values
from a business object into a DataTable or DataSet:
adapter.Fill(dataset, source);
adapter.Fill(dataset, "TableName", source);
adapter.Fill(datatable, source);
If the source object is a single object, then one row of data is added to the DataTable or
DataSet. If the source object is a collection, then one row of data is added to the DataTable or
DataSet for each item in the collection.
Things are slightly more complex if the business object graph has several levels of object. For
example, an OrderEdit object containing a child collection of LineItemEdit objects will require two
Because the target DataTable object is empty, the Fill method will automatically add all
necessary column definitions before copying the source object’s properties into the DataTable.
You can use the ObjectAdapter class to convert business objects into DataTable or DataSet
objects when the application requirements need one of these older ADO.NET data types.
SafeDataReader Class
One of the basic ADO.NET data types is the data reader. All data reader objects implement the
IDataReader interface from the System.Data namespace, and every ADO.NET provider
implementation includes a data reader.
One of the most common issues application developers face when reading data from a database
is that some database columns allow null data values that have no meaning to the application.
When those null data values are read from the database they must be converted into some
meaningful non-null value for use by the application.
There are two major reasons for using null data values in a database:
The second reason, values that have yet to be entered, only has meaning if the business cares
about the difference between an empty value and a value that has never been entered. For a
numeric type this means that there is a business difference between a zero and a value that hasn’t
been entered at all.
This is a valid concern, because in some applications there is a big difference between a zero
entered by a user, and a value that hasn’t been entered. For most applications, this sort of
distinction has no meaning.
In my experience, a lot of databases allow null values in columns where no null values should be
allowed. I am sure there are many reasons why this occurs, but the end result is that many
application developers are left reading data from the database and having to convert null data
values into a meaningful equivalent, such as 0, false, string.Empty, etc.
The SafeDataReader class is a data reader implementation that wraps any other IDataReader
and automatically removes all null data values that come from the database. The goal of
SafeDataReader is to simplify data access code that uses a data reader, so the data access code
never has to worry about getting a null data value.
The ExecuteReader method is called on the command object (cm), and the result of that method
is wrapped in a new SafeDataReader object. The SafeDataReader class can wrap any IDataReader
type, and since all data readers implement this interface, it can wrap any data reader object.
The resulting SafeDataReader object is used exactly like a normal data reader, except that any
null data values are automatically converted into the non-null default value for the data type. For
example, a null string value is converted to string.Empty, and a null numeric value is converted to
0.
One other nice feature of SafeDataReader is that it allows the direct use of the column name
instead of its ordinal position value. In the code above, you can see how the GetString method
directly accepts the column name instead of the numeric column position. Assuming the FirstName
column is column number 1, the following three lines of code are equivalent:
result.FirstName = dr.GetString("FirstName");
result.FirstName = dr.GetString(dr.GetOrdinal("FirstName"));
result.FirstName = dr.GetString(1);
You should consider using SafeDataReader if your application doesn’t have a business
requirement to differentiate between empty data values and values never entered by a user.
At this point I have discussed the utility types available in the Csla.Data namespace. In Chapter
4 I will discuss how to create data access layers in the encapsulated invoke and factory
implementation models.
1. Encapsulated invocation
2. Factory implementation
3. Factory invocation
4. Encapsulated implementation
The two models I recommend for most applications are encapsulated invocation and factory
implementation, so these are the models I will cover in detail.
Encapsulated invocation allows the data portal to manage the metastate of the business objects,
while enabling clean separation of the data access implementation.
Factory implementation enables clean separation of the data access implementation, along with
enabling a high degree of flexibility in how your data access code manipulates the state and
metastate of the business objects.
The other two models are variations on the same concepts, but each has drawbacks. Factory
invocation adds a redundant layer of indirection that usually introduces more complexity and
overhead than can be justified for an application. Encapsulated implementation is the simplest of all
the models, but doesn’t enable separation of the data access implementation from the business
classes and so it is also the least flexible.
In this chapter I will discuss some options for implementing an external Data Access layer that
can be invoked by a DataPortal_XYZ method or factory object method.
In Chapters 5 and 6 I will then move on to demonstrate how to implement data access for a set
of business objects using the two data portal models I generally recommend: encapsulated
invocation and factory implementation. The other two data portal models are variations on these
concepts, so once you understand the two models I’ll demonstrate in this ebook you should be able
to implement the other models if necessary.
When the DAL is external, the data access invocation code is responsible for invoking the DAL to
get, save, or delete data. This invocation code might be in your DataPortal_XYZ methods, or it
might be in your factory object methods. Either way, the DAL must expose some formal interface
that can be invoked.
External DAL components are usually loaded dynamically at runtime. This allows the DAL
components to be swapped for other components, resulting in a “pluggable DAL”. I recommend at
least implementing your real DAL and a “mock” DAL that provides hard-coded data values for
testing of the application. You can also use a pluggable DAL to allow an application to work against
multiple types of database, such as SQL Server, Oracle, and DB2.
It is also the case that some code must interact with the private state and metastate of the
business object to get and set the object’s properties and metastate. As I’ve already discussed, this
can be done in a way that preserves encapsulation by using the DataPortal_XYZ methods, or it can
be done by breaking encapsulation with factory objects and the ObjectFactory base class.
I’ll cover all these concepts, starting with options for the DAL interface.
The methods that Fetch data return their results through an IDataReader object. This is the
interface defined by ADO.NET for all data reader objects, so these Fetch methods could be getting
the data from SQL Server, Oracle, or any other data source with support for ADO.NET.
The Insert method defines parameters for every data value that is required in the database.
The method also returns an int value. That value is the new primary key value generated by the
database during the insert operation.
The Update method defines parameters for every data value necessary to perform the update
operation in the database.
The Delete method requires the primary key value for the data entity so it can implement the
delete operation.
I will demonstrate implementations of this interface later in the chapter as I discuss the
EncapsulatedInvoke sample application.
It is database neutral and will work with any database that supports ADO.NET
Performance is usually high because the DAL can use direct ADO.NET concepts
The interface is strongly-typed and that helps make the code more readable and
maintainable
Some business objects contain or interact with data from multiple tables or data entities. In that
case, the data access invocation code will call methods on multiple DAL objects.
Every instance of PersonDto is composed of public read-write properties that provide strongly
typed access to the data.
Objects designed this way are for data transfer because they are easily serialized into XML, JSON,
or other formats. And XML, JSON, and other formatted data can be easily deserialized into a DTO.
This is because reflection or dynamic property invocation can be used to get and set every property
value.
This is entirely unlike a typical business domain object, where some properties are read-only,
and most properties have authorization and business rules that may prevent property values from
being read or set by a serialization component.
Here’s an example of a data access interface that uses DTOs:
public interface IPersonDal
{
List<PersonDto> Fetch();
PersonDto Fetch(int id);
void Insert(PersonDto data);
void Update(PersonDto data);
void Delete(int id);
}
Notice that the methods are similar to the data reader example, and include support for reading,
inserting, updating, and deleting data. Instead of using a data reader, this interface uses the DTO
type or a list of the DTO type.
I will demonstrate implementations of this interface later in the chapter as I discuss the
EncapsulatedInvokeDto sample application.
This type of interface is more abstract than the data reader approach, because it completely
avoids the use of any ADO.NET data types. There is nothing in this interface that requires the
concrete DAL implementations to use ADO.NET. If you are building a concrete DAL that doesn’t use
a database, the DTO approach is often a better solution than using a data reader. Examples of non-
database DAL implementations include:
You can use the DTO approach when building a concrete DAL that does use a database too. The
result is that the DTO approach can work with nearly any DAL you can imagine, while the data
reader approach is generally more useful for DAL implementations that work against a database
supported by ADO.NET.
The primary advantage of the DTO approach is the higher level of abstraction. The primary
drawback to the DTO approach is that it requires more code, and usually, more overhead.
If these values are included in the DTO, then the interface doesn’t need separate Insert and
Update methods, and even the Delete method can be eliminated:
public interface IPersonDal
{
List<PersonDto> Fetch();
PersonDto Fetch(int id);
void Update(PersonDto data);
}
The reason the Insert and Delete methods are no longer required is that the implementation of
the Update method can now use the IsNew and IsDeleted properties from the DTO to determine
what kind of action is required:
public void Update(PersonDto data)
{
if (data.IsDeleted)
{
if (!data.IsNew)
{
// delete data
}
data.Id = -1; // reset primary key value
}
else if (data.IsNew)
{
// insert data
// set data.Id to database-generated value
}
else
{
// update data
}
}
Exceptions in .NET
The data portal is designed with the idea that when a data operation fails the result is an exception.
One thing you should consider when building pluggable DAL components, is that exceptions are
part of the interface.
If an insert operation occurs because of a duplicate key or other data integrity violation, the
ADO.NET provider for the database will throw an exception. The exception thrown by SQL Server
will be different from that for Oracle or other database providers.
At some level in your application, your code will need to catch and handle this exception. Many
exceptions flow back to the client, possibly to the Interface Control layer. Ideally, the code in that
layer won’t need to catch every possible type of exception from every database your application
might use.
To avoid that problem, you may choose to define your own exception types for each possible
failure condition. In your concrete DAL implementations, you can then handle any exceptions
specific to each database provider and rethrow your custom exception type. This helps ensure that
only your custom exceptions flow up to higher layers in the application.
Here’s an example exception class for the .NET platform:
[Serializable]
public class DataNotFoundException : Exception
{
public DataNotFoundException(string message, Exception innerException)
: base(message, innerException)
{ }
protected DataNotFoundException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context)
{ }
[SecurityPermission(
SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
[SecurityPermission(
SecurityAction.Demand, Flags = SecurityPermissionFlag.SerializationFormatter)]
public override void GetObjectData(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
{
base.GetObjectData(info, context);
}
}
As a result, any custom exceptions you create and use in your DAL implementation will not be
directly returned to a Silverlight client, but the data contained within the exception will be available
to client-side code.
For example, the data portal uses a provider pattern to dynamically load the appropriate object
factory types by default. As I discussed earlier in this book, the factory loader component
dynamically loads the correct type for each object factory, and creates instances of the factory
objects as needed.
You can also choose to implement your own provider pattern, or you might use an inversion of
control (IoC) framework and container to dynamically load your DAL types. Examples of IoC
frameworks include the Unity framework from Microsoft Patterns and Practices, and the open
source Castle Winsor project.
When testing business objects, you need to be able to load each object graph with known values
so you can perform tests against those values. Although it is possible to re-initialize a real SQL
database before each test run, it is far easier to use a mock database that automatically initializes
each time it is used. Additionally, you can avoid much of the configuration complexity that often
comes with using a physical database, because the mock database is usually an in-memory
construct.
Using a mock database also ensures that you create at least two DAL implementations. This
makes it harder to make accidental implementation choices that prevent the DAL from being
pluggable.
When building a pluggable DAL, it is extremely easy to take implementation shortcuts or make
other mistakes that eventually prevent the application from swapping from one DAL
implementation to another. The only guaranteed way to prevent such mistakes is to create at least
two DAL implementations from the start of the project. Creating a DAL for your real database and
for your mock database achieves this goal.
Each “table” is a List<T> where T is a simple entity type containing public read-write properties
that represent each column of data. For example:
Using CSLA 4: Data Access Page 88
Rev 1.0
public class CategoryData
{
public int Id { get; set; }
public string Category { get; set; }
}
Finally, it is necessary to load the mock database with known data values. This initialization
process should be consistent every time to enable business object tests to be written against these
known values. You can hard-code the values, or load them from a file, or some other source.
I typically load the values in the static constructor of the class containing the “table
definitions”. For example, here’s the code that loads the Categories table:
static MockDb()
{
Categories = new List<CategoryData>
{
new CategoryData { Id = 0, Category = "Misc" },
new CategoryData { Id = 1, Category = "Employee" },
new CategoryData { Id = 2, Category = "Vendor" },
new CategoryData { Id = 3, Category = "Customer" }
};
This creates the list object, and populates it with a set of new entity objects containing hard-
coded values for testing.
In this example, I’m using the First method, and that will result in an exception if the row is not
found. You may also choose to implement fetch actions so they don’t immediately throw a “key not
found” exception, in which case you would use the FirstOrDefault method.
The behavior of each mock DAL action should exactly match the behavior of the real
DAL action.
If the real DAL throws exceptions when the row isn’t found, the mock DAL should also throw an
exception. If the real DAL doesn’t throw an exception, then the mock DAL shouldn’t throw an
exception either.
An insert action is simply a matter of creating a new entity object, populating it with values, and
adding it to the table. For example:
var newId = MockDb.MockDb.Persons.Max(r => r.Id) + 1;
var item = new MockDb.PersonData { Id = newId, FirstName = firstName, LastName = lastName };
MockDb.MockDb.Persons.Add(item);
To implement an update action, the existing row must be found, and the existing values
updated. For example:
Finally, the delete action finds the existing row and removes it from the list:
var item = MockDb.MockDb.Persons.Where(r => r.Id == id).FirstOrDefault();
if (item != null)
MockDb.MockDb.Persons.Remove(item);
The examples I’m showing here demonstrate how to get, insert, update, and delete data in an in-
memory mock database. You will use similar code to create the mock DAL implementations that use
the mock database.
In the next chapter, I will move on to discuss the implementation of the encapsulated invoke and
factory implementation data access models.
Each concrete DAL project implements the interfaces defined in the DAL interface assembly. One
concrete DAL might interact with SQL Server, another with Oracle, and still another might use hard-
coded mock data for testing purposes. Because they all implement the same interfaces, each
concrete DAL is interchangeable with the others, and can be dynamically loaded at runtime.
The DAL interface assembly often contains the provider pattern or IoC implementation
necessary to dynamically load the appropriate concrete DAL assembly at runtime. This is usually
done based on configuration values in the application’s web.config or app.config file.
In the EncapsulatedInvoke and EncapsulatedInvokeDto sample applications, I am using a
provider pattern that uses an entry in the application’s config file to determine which DAL
implementation to load at runtime. Both samples include a database implementation that uses a
SQL Server Compact Edition (SqlCe) implementation using direct ADO.NET data access. They also
include an implementation using the ADO.NET Entity Framework to interact with a SQL Server
Using CSLA 4: Data Access Page 91
Rev 1.0
Express database. And they include a mock DAL implementation that operates against simple hard-
coded values in memory.
I will walk through the entire persistence process, including implementation of the Create, Fetch,
Update, Delete, and Execute operations. Before I do that, I’ll discuss the DAL provider
implementation in more detail.
Figure 11. DataAccess project contains DAL interface definitions and loader
This project contains the interface definitions and DTO implementations used by the concrete
DAL implementations. The project also contains the code that dynamically loads the concrete DAL
provider based on the application’s configuration.
When a DataPortal_XYZ method needs to interact with the data store, it asks the DalFactory
class (from the DataAccess project) to return an object that knows how to create concrete
implementations of the required DAL types. That DAL type “manager” object can then be used to
get objects that provide a specific implementation of each DAL action.
Figure 12 illustrates how the DataPortal_XYZ method uses the DalFactory to get a DalManager.
The DalManager then provides the DataPortal_XYZ method with a reference to a PersonDal object
that is a concrete implementation of the IPersonDal interface.
The first step is to call the GetManager method on the DalFactory class to get an object that
knows how to return the appropriate implementations of each DAL interface type defined in the
DataAccess assembly. Remember from Figure 10 that the business library and each DAL provider
reference the DataAccess assembly. That assembly provides the definitions for all DAL types used
by the rest of the code.
The GetManager method uses the GetType method of the Type class from .NET to create a Type
object based on that full type name. That Type object is cached so this work only occurs once per
execution of the application.
The value of the _dalType field is then used to create an instance of the IDalManager
implementation each time the GetManager method is called.
This DAL manager object is responsible for returning DAL provider objects that implement each
of the interfaces defined in the DataAccess assembly.
There are several ways you might implement the GetProvider method, including hard coding
the results in a big switch statement. In my sample applications I chose to use reflection to get the
type name of the interface, and to then dynamically rewrite that type name so “IPersonDal”
becomes “MyProvider.PersonDal”:
private static string _typeMask = typeof(DalManager).FullName.Replace("DalManager", @"{0}");
The _typeMask field gets the full type name of the current type: MyProvider.DalManager. The
“DalManager” class name is replaced with {0} to create a string format mask: “MyProvider.{0}”.
In the GetProvider<T> method, the type name of T is retrieved. This will be a value such as
IPersonDal or ICategoryDal. The “I” prefix is removed, and the resulting value is then applied to
the _typeMask value to get a resulting value such as “MyProvider.PersonDal”.
public DalManager()
{
ConnectionManager = ConnectionManager<SqlCeConnection>.GetManager("LocalDb");
}
This implementation uses the ConnectionManager class from Csla.Data to ensure any already-
open connection is automatically reused. I discussed the ConnectionManager type in Chapter 3.
When the DalManager object is disposed, it disposes the ConnectionManager object it contains.
And the ConnectionManager object disposes the SqlCeConnection object it contains when there
are no more users of that connection.
Similarly, the DataAccess.SqlEf provider implements the same behavior, but using an
ObjectContextManager object:
public ObjectContextManager<SqlDbEntities> ConnectionManager { get; private set; }
public DalManager()
{
ConnectionManager = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities");
}
Again, to ensure that the database connection is held open and reused by all data access code,
the DalManager object creates an ObjectContextManager in its constructor, and disposes that
object when the DalManager object is disposed.
Using CSLA 4: Data Access Page 95
Rev 1.0
Implementing a Data Reader DAL Interface
Each DAL provider assembly contains classes that implement every DAL interface defined in the
DataAccess assembly. Figure 13 is an example of a project that implements a concrete provider of
the interfaces defined in Figure 11.
Every DAL provider will provide an implementation of ICategoryDal. The specific code in each
provider may be very different, but they are interchangeable as long as they all implement the
same interface and provide consistent behaviors.
“Consistent behaviors” means that each implemention throws exceptions and returns results in
a consistent manner. If one Fetch method implementation throws an exception when no data is
found, then all Fetch method implementations must throw an exception when no data is found. If
one Delete method implementation silently fails if there’s no data to delete, then all Delete
method implementations must silently fail in that situation.
Notice how the Fetch method returns a List<CategoryDto> instead of an IDataReader, and
how the Insert and Update methods accept a CategoryDto object instead of a list of parameters. In
some ways this DAL interface is cleaner than with the data reader example, but it does require the
implementation of a DTO type for every data entity.
As with the data reader based DAL, it is important that every DAL provider provide consistent
behaviors in terms of returning data or throwing exceptions. Even though the Mock, SqlEf, and
SqlCe implementations are very different, they all provide the same behaviors when invoked.
The database access is handled by EF using a standard object context, and the results from the
EF query are used to populate a ListDataReader object. You can find the ListDataReader class in
the SqlEf project.
Similarly, the SqlEf provider implementation in the EncapsulatedInvokeDto solution must
conform to the DTO-based interface defined by the interfaces in that solution’s DataAccess project.
Here’s an example of a Fetch method in this implementation:
public List<CategoryDto> Fetch()
{
using (var ctx = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities"))
{
var data = from r in ctx.ObjectContext.CategoryTables
select new CategoryDto { Id = r.Id, Category = r.Category };
return data.ToList();
}
}
The EF query is very similar, but instead of wrapping a list of entity objects in an IDataReader,
this implementation puts the data from the query into a list of the DTO types defined in the
DataAccess project.
It is possible to define a DAL interface that is based on EF entity types. If you do this, all your DAL
implementations will be required to conform to that interface. This can be challenging, since the
default behavior of the EF model designer tooling will create different entity types each time you
generate an entity model from a database.
For example, if you have two identical databases, one in SQL Server and another in Oracle, you’ll
end up (by default) with two similar entity models, each with different entity types. This means they
can’t conform to the same common type scheme and therefore can’t be pluggable DAL
implementations.
You can use model-first concepts supported by EF, where you manually create a model and then
map it to each database. And future versions of EF are planned to support something called code-
first design, where you manually create .NET classes to contain the data, and then map each of
those class types to tables in the database.
The model-first and code-first options require more manual effort, but do enable the idea of
multiple DAL implementations that conform to an interface defined by common entity types. In
both of these scenarios, your common model or entity types will be located in a shared assembly
that is referenced by all individual DAL provider implementations.
The provider model I just discussed will be used as I discuss how to implement persistence using
the encapsulated invoke model with data reader and DTO style provider interfaces. I’ll now
Using CSLA 4: Data Access Page 98
Rev 1.0
demonstrate persistence for each business object stereotype, starting with the editable root
stereotype.
DataReader Interface
The DataAccess project in the EncapsulatedInvoke solution includes the IPersonDal interface:
public interface IPersonDal
{
IDataReader Fetch();
IDataReader Fetch(int id);
int Insert(string firstName, string lastName);
void Update(int id, string firstName, string lastName);
void Delete(int id);
}
This interface defines the data access operations for the person data entity. This DAL interface is
used to persist the PersonEdit editable root object, and the PersonList read-only list object (which
I’ll discuss later in this chapter).
The DataAccess.Mock, DataAccess.SqlCe, and DataAccess.SqlEf projects contain PersonDal
classes. Each class implements this IPersonDal interface in a different way, but with consistent
behaviors.
Each data access action includes data access invocation and data access implementation.
Because these samples are following the encapsulated invoke model, the data access invocation is
in DataPortal_XYZ or Child_XYZ methods contained in each business class. The data access
implementation is located in the Mock, SqlEf, and SqlCe DAL provider projects.
Create Operation
The create action starts with the NewPersonEdit factory methods in the PersonEdit class:
#if SILVERLIGHT
public static void NewPersonEdit(EventHandler<DataPortalResult<PersonEdit>> callback)
{
DataPortal.BeginCreate<PersonEdit>(callback, DataPortal.ProxyModes.LocalOnly);
}
#else
public static void NewPersonEdit(EventHandler<DataPortalResult<PersonEdit>> callback)
{
DataPortal.BeginCreate<PersonEdit>(callback);
}
Using CSLA 4: Data Access Page 99
Rev 1.0
public static PersonEdit NewPersonEdit()
{
return DataPortal.Create<PersonEdit>();
}
#endif
These methods invoke the client-side data portal to create and initialize a new instance of the
business class. The asynchronous method is slightly different between Silverlight and .NET, and the
synchronous method is only available on .NET.
The client-side data portal invokes the server-side data portal based on the client configuration.
The result is that the DataPortal_Create method in the PersonEdit class is invoked. In this
example I’m showing the Silverlight and .NET implementations of the method:
#if SILVERLIGHT
public override void DataPortal_Create(
Csla.DataPortalClient.LocalProxy<PersonEdit>.CompletedHandler handler)
{
using (BypassPropertyChecks)
{
Id = -1;
}
base.DataPortal_Create(handler);
}
#else
[RunLocal]
protected override void DataPortal_Create()
{
using (BypassPropertyChecks)
{
Id = -1;
}
base.DataPortal_Create();
}
#endif
In both implementations, this method initializes the new object with default values. The base
implementation of DataPortal_Create is then invoked. This base implementation runs all business
rules associated with the object and its properties. Usually this is desirable, because required fields
are marked as invalid, ensuring that an empty object can’t be saved with invalid data.
The NewPersonEdit factory method for Silverlight sets the data portal’s proxy mode to
LocalOnly, and that prevents the data portal from attempting to make a cross-network call to run
the DataPortal_Create method. This is good, because this DataPortal_Create method doesn’t
interact with the database or DAL, so the code can run on the client or server. It is more efficient to
have the code run on the client.
In the .NET implementation, notice the use of the RunLocal attribute. Again, because this
method doesn’t interact with the database or DAL, this code can run on the client or server. The
RunLocal attribute prevents the .NET data portal from attempting to make a cross-network call to
run this method.
If your DataPortal_Create method does interact with the DAL to load default values for the new
object, you should not use the LocalOnly proxy mode in Silverlight or the RunLocal attribute in
.NET. That will allow the data portal to make the appropriate cross-network call so the
DataPortal_Create method runs on an application server (in a 3- or 4-tier deployment) where it
can access the database.
Using CSLA 4: Data Access Page 100
Rev 1.0
In any case, the data portal automatically ensures that this new object’s metastate is set
correctly, so IsNew is true, IsDirty is true, and IsValid is true or false depending on the
business rules defined for the object.
Fetch Operation
The fetch action starts with the GetPersonEdit factory methods in the PersonEdit class:
public static void GetPersonEdit(int id, EventHandler<DataPortalResult<PersonEdit>> callback)
{
DataPortal.BeginFetch<PersonEdit>(id, callback);
}
#if !SILVERLIGHT
public static PersonEdit GetPersonEdit(int id)
{
return DataPortal.Fetch<PersonEdit>(id);
}
#endif
These methods invoke the client-side data portal to create an instance of the business class and
load that object with pre-existing data from the database. The client-side data portal invokes the
server-side data portal based on the client configuration. The server-side data portal then invokes
the DataPortal_Fetch method of the PersonEdit object:
private void DataPortal_Fetch(int id)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IPersonDal>();
using (var data = dal.Fetch(id))
{
data.Read();
using (BypassPropertyChecks)
{
Id = data.GetInt32(data.GetOrdinal("Id"));
FirstName = data.GetString(data.GetOrdinal("FirstName"));
LastName = data.GetString(data.GetOrdinal("LastName"));
}
}
}
}
The code in this method gets the DAL manager object from the DalFactory class. The DAL
manager object is wrapped in a using block so it is properly disposed when the action is complete.
The GetProvider method of the DAL manager is called to get an instance of the IPersonDal
provider. Notice that this code doesn’t know or care what provider is returned, only that some valid
implementation of IPersonDal is made available.
The Fetch method defined by IPersonDal returns an IDataReader object. That object is used to
retrieve the data from the database. The assumption is that the DAL Fetch method has done
whatever was necessary to create and return an open data reader containing the requested data.
You may choose to wrap the Fetch result in a SafeDataReader so it can automatically remove
null data values returned from the database. I discussed the SafeDataReader type in Chapter 3.
Because it implements the IDataReader interface, you can choose to return a SafeDataReader from
the DAL Fetch method itself, or wrap the Fetch method result in the DataPortal_Fetch method.
For example:
Using CSLA 4: Data Access Page 101
Rev 1.0
using (var data = new Csla.Data.SafeDataReader(dal.Fetch(id)))
The Read method is called on the data reader to move to the first row of returned data.
Next, the code enters a using block for the BypassPropertyChecks object of the business object.
This suppresses business and authorization rule checking for the object’s properties, meaning that
the properties can be set to the values from the data reader without incurring the overhead and
potential failure scenarios that could occur if the rules were run normally.
In many applications, the data from the database is trusted, and so there’s no need to run the
business rules against data that was just retrieved from the database. That’s the case in this sample
implementation.
In other situations, you may feel the need to run the business rules after the object has been
loaded with data from the database. If you do need to run the business rules once the object has
been loaded with data, you will need to manually call the CheckRules method of the
BusinessRules object at the bottom of the DataPortal_Fetch method. I recommend that this be
the last line of code in the method:
BusinessRules.CheckRules();
ADO.NET Provider
The DataAccess.SqlCe provider implements the Fetch method like this:
public System.Data.IDataReader Fetch(int id)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var cm = ctx.Connection.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,FirstName,LastName FROM Person WHERE Id=@id";
cm.Parameters.Add("@id", id);
return cm.ExecuteReader();
}
}
The ConnectionManager type from Csla.Data is used to get the existing database connection. As
I discussed earlier in this chapter, the database connection is already open, because the DalManager
object will have opened it before any DAL provider methods are invoked.
The database connection is then used to create a command object for the query, and that
command object is executed to return an IDataReader object as required by the IPersonDal
interface.
The query runs against the People collection of the EF ObjectContext object to retrieve a list of
entity objects that match the where clause.
Because the IPersonDal interface requires that the Fetch method return an IDataReader, the
result of the EF query is wrapped in a ListDataReader object that implements the IDataReader
interface. The ListDataReader class can be found in the DataAccess.SqlEf project.
Mock Provider
The DataAccess.Mock provider has a different implementation that uses a LINQ to Objects query:
public System.Data.IDataReader Fetch(int id)
{
return new ListDataReader<MockDb.PersonData>(MockDb.MockDb.Persons.Where(r => r.Id == id));
}
The LINQ Where method filters the results based on the id parameter value, and those results
are wrapped in a ListDataReader object.
The ListDataReader class can be found in the DataAccess.Mock project. It is a type I use for
creating mock DAL implementations. The ListDataReader type implements the IDataReader
interface, using the contents of a list, collection, or LINQ query result as the data source.
At this point you should understand how the client-side factory methods invoke the data portal,
and the data portal then invokes the DataPortal_Fetch method. And you should understand how
the DataPortal_Fetch method uses the DalFactory to get an IDalManager object for the DAL
provider. That DAL manager provides access to an implementation of the DAL type (IPersonEdit in
this example) so the DataPortal_XYZ method can call its Fetch method. The results of the Fetch
method are used to load the business object with data. The Fetch method itself may be
implemented in various ways by different DAL providers, as long as all implementations conform to
the IPersonDal interface and provide consistent behaviors.
Insert Operation
When an editable root object is saved, the Save or BeginSave method invokes the client-side data
portal by calling its Update or BeginUpdate method. That client-side method invokes the server-side
data portal based on the client configuration, and the server-side data portal the invokes one of
three methods on the business object:
1. DataPortal_Insert
2. DataPortal_Update
3. DataPortal_DeleteSelf
As I’ve previously discussed, the data portal uses the business object’s IsNew and IsDeleted
metastate properties to determine which of these methods should be invoked.
The DataPortal_Insert method is responsible for inserting data from a new object into the
database by using the DAL implementation:
Notice the use of the Transactional attribute. Most insert, update, and delete actions will be
transactional to ensure that database integrity is preserved.
As with the DataPortal_Fetch method, the first thing this method does is get the IDalManager
object from the DalFactory class. The specific IDalManager implementation returned is based on
the application configuration.
The DAL manager’s GetProvider method is then used to get the concrete implementation of the
IPersonDal interface, so the DAL Insert method can be invoked to perform the insert action.
It is important to notice that all use of the business object’s properties are contained in a using
block for the BypassPropertyChecks object. This prevents business and authorization rules from
being run as these properties are used.
Again, this code is independent of any specific DAL implementation, and the code in the
DataAccess.Mock, DataAccess.SqlEf, and DataAccess.SqlCe projects are quite different. You can
look at the Mock implementation in the code download.
ADO.NET Provider
Here’s the SqlCe implementation of the Insert method:
public int Insert(string firstName, string lastName)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "INSERT INTO Person (FirstName,LastName) VALUES (@firstName,@lastName)";
cm.Parameters.Add("@firstName", firstName);
cm.Parameters.Add("@lastName", lastName);
cm.ExecuteNonQuery();
cm.Parameters.Clear();
cm.CommandText = "SELECT @@identity";
var r = cm.ExecuteScalar();
var newId = int.Parse(r.ToString());
return newId;
}
}
}
This method gets the connection to the database, sets up a command object to do the insert,
and executes that command object against the database. The database generates a new unique Id
value for the inserted row.
Because this is a SqlCe database, retrieving the new Id value for the inserted row is a separate
step from the insert query. The command object’s ExecuteNonQuery method is used to perform the
Using CSLA 4: Data Access Page 104
Rev 1.0
insert, and then a second command is executed with the ExecuteScalar method to retrieve the
@@identity value from the database.
When using full SQL Server you would retrieve this new Id value by calling the SCOPE_IDENTITY
SQL method as part of the database query. So the CommandText would look like this:
"INSERT INTO Person (FirstName,LastName) VALUES (@firstName,@lastName);
SELECT SCOPE_IDENTITY()"
In that case, there would be only one execution of a command object, and that is done using the
ExecuteScalar method to perform the insert and retrieve the new Id value in one database call.
This method creates a new instance of the Person entity that was generated from the EF edmx
file. The properties of that entity object are loaded with data, and the object is added to the EF
ObjectContext object’s People collection. Then the changes to the ObjectContext are committed
by calling its SaveChanges method.
As part of the update process, EF automatically retrieves the new database-generated Id
property value and puts it into the entity. That is the value returned as the result of the Insert
method.
Update Operation
The DataPortal_Update method is responsible for updating data from an existing object into the
database. It is invoked by the server-side data portal in response to a Save or BeginSave method
call on the client.
Here’s the DataPortal_Update method from the PersonEdit class:
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Update()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IPersonDal>();
using (BypassPropertyChecks)
{
dal.Update(Id, FirstName, LastName);
}
}
}
ADO.NET Provider
The Update method in the PersonDal class from the SqlCe provider looks like this:
public void Update(int id, string firstName, string lastName)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "UPDATE Person SET FirstName=@firstName,LastName=@lastName WHERE Id=@id";
cm.Parameters.Add("@id", id);
cm.Parameters.Add("@firstName", firstName);
cm.Parameters.Add("@lastName", lastName);
var rowsAffected = cm.ExecuteNonQuery();
if (rowsAffected == 0)
throw new DataNotFoundException("Person");
}
}
}
As with the Insert method, this code gets the database connection, and then sets up and
executes a command object to perform the update action.
person.FirstName = firstName;
person.LastName = lastName;
var count = ctx.ObjectContext.SaveChanges();
if (count == 0)
throw new InvalidOperationException("PersonDal.Update");
}
}
Updating data with EF can be done in a couple ways. The simplest, but less efficient approach
involves the following steps:
3. Save changes to the entity with the ObjectContext object’s SaveChanges method
Although the code to implement that approach is simple, it means reading the data from the
database in order to do an update, so it involves two database interactions.
Using CSLA 4: Data Access Page 106
Rev 1.0
The implementation in the Update method shown here uses a slightly more complex, but also
more efficient approach. It involves the following steps:
3. Create an EntityKey object, and load it with the entity’s primary key information
4. Set the Person object’s EntityKey property to this new EntityKey object
5. Attach the Person entity object to the ObjectContext object’s People collection
This approach requires more code, but only requires one database interaction to perform the
table update.
I’ll discuss immediate deletion later in this chapter, but for now it is enough to know that the
DataPortal_Delete method will invoke the Delete method on the DAL provider object.
If your business class doesn’t support immediate deletion, the DataPortal_DeleteSelf method
will invoke the delete action directly:
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_DeleteSelf()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IPersonDal>();
using (BypassPropertyChecks)
{
dal.Delete(Id);
}
}
}
You can see how this code is similar to the Insert and Update methods. It gets the DAL provider
object and invokes the Delete method defined by the IPersonDal interace.
Using CSLA 4: Data Access Page 107
Rev 1.0
ADO.NET Provider
The SqlCe implementation of the Delete method looks like this:
public void Delete(int id)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "DELETE Person WHERE Id=@id";
cm.Parameters.Add("@id", id);
var rowsAffected = cm.ExecuteNonQuery();
if (rowsAffected == 0)
throw new DataNotFoundException("Person");
}
}
}
Like the Insert and Update methods, this implementation gets the database connection and
sets up a command object. The command object is executed to delete the data, throwing an
exception if there was no data to delete.
You should understand that a “delete” operation doesn’t necessarily need to delete any data. In
some applications a delete operation updates each row to set a “deleted flag” indicating that the
row of data is no longer active. Although this example does delete rows of data from the database,
you could implement the Delete method to perform an update of the existing row instead of
deleting any data.
Retrieving the entity in order to delete it is somewhat inefficient because it requires two
database interactions, but EF requires that the entity be retrieved so it can properly delete the
entity and any related data.
The client-side data portal invokes the server-side data portal, and it then invokes the
DataPortal_Delete method on the business object:
[Transactional(TransactionalTypes.TransactionScope)]
private void DataPortal_Delete(int id)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IPersonDal>();
dal.Delete(id);
}
}
This method invokes the same DAL provider Delete method I discussed in the previous section
about deferred deletion.
At this point you should understand how to implement persistence for an editable root object
with a data reader based DAL implementation. I’ll now revisit the same editable root object
scenario, but with a DTO-based DAL implementation.
DTO Interface
The DataAccess project in the EncapsulatedInvokeDto solution includes the IPersonDal interface:
public interface IPersonDal
{
List<PersonDto> Fetch();
PersonDto Fetch(int id);
void Insert(PersonDto data);
void Update(PersonDto data);
void Delete(int id);
}
This interface defines the data access operations for the person data entity. This DAL interface is
used to persist the PersonEdit editable root object, and the PersonList read-only list object (which
I’ll discuss later in this chapter).
The DataAccess.Mock, DataAccess.SqlCe, and DataAccess.SqlEf projects contain PersonDal
classes. Each class implements this IPersonDal interface in a different way, but with consistent
behaviors.
Each data access action includes data access invocation and data access implementation.
Because these samples are following the encapsulated invoke model, the data access invocation is
in DataPortal_XYZ or Child_XYZ methods contained in each business class. The data access
implementation is located in the Mock, SqlEf, and SqlCe DAL provider projects.
Notice that the interface relies on a PersonDto type. This is the data transfer object type that
provides a consistent data contract for use by the business object and any DAL provider
implementations:
public class PersonDto
{
public int Id { get; set; }
public string FirstName { get; set; }
The DTO type defines properties for each value that must flow between the data access
invocation code and the data access implementation code. The type is defined in the DataAccess
project so it is available to the business classes and DAL provider implementations. Please refer
back to Figure 10 to see how the business library and all DAL provider assemblies reference the
DataAccess assembly.
As I discuss the data access actions and how they are implemented, I won’t repeat the discussion
from the data reader implementation. For example, the factory methods in the PersonEdit class
are unaffected by the DAL implementation choices and so I won’t repeat those methods here.
Create Operation
The create action is implemented exactly the same in as in the EncapsulatedInvoke solution.
Please refer to that earlier discussion for details.
Fetch Operation
In the fetch action the server-side data portal invokes the DataPortal_Fetch method on the
PersonEdit business object. This method invokes the DAL to get back a PersonDto object
containing the person data from the database:
private void DataPortal_Fetch(int id)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IPersonDal>();
var data = dal.Fetch(id);
using (BypassPropertyChecks)
{
Id = data.Id;
FirstName = data.FirstName;
LastName = data.LastName;
}
}
}
The result of the Fetch method is a PersonDto object containing the data values from the
database. Those values are used to load the business object with data.
Notice that the object’s properties are set within a using block for the BypassPropertyChecks
object to suppress rule checking. As in the data reader implementation, if you need to run business
rules once the business object has been loaded with data, you should add an explicit call to the
CheckRules method of BusinessRules as the last line of code in the DataPortal_Fetch method.
The DataAccess.Mock DAL provider includes a PersonDal class that implements the IPersonDal
interface from the DataAccess assembly. Its Fetch method looks like this:
public PersonDto Fetch(int id)
{
var data = from r in MockDb.MockDb.Persons
where r.Id == id
select new PersonDto { Id = r.Id, FirstName = r.FirstName, LastName = r.LastName };
if (data.Count() == 0)
throw new DataNotFoundException("Person");
return data.First();
}
Using CSLA 4: Data Access Page 110
Rev 1.0
This code uses a LINQ query to retrieve the appropriate row of data from the mock Persons
table. That data is placed into a new PersonDto object, and that object is returned as the result of
the method.
Notice that an exception is thrown if no matching data is found.
The DataAccess.SqlCe DAL provider also implements a Fetch method:
public PersonDto Fetch(int id)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var cm = ctx.Connection.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,FirstName,LastName FROM Person WHERE Id=@id";
cm.Parameters.Add("@id", id);
using (var dr = cm.ExecuteReader())
{
dr.Read();
var result = new PersonDto
{ Id = dr.GetInt32(0), FirstName = dr.GetString(1), LastName = dr.GetString(2) };
return result;
}
}
}
This implementation gets the database connection and sets up a command object to retrieve the
requested data. That command object is executed to get a data reader, and the values from the
data reader are used to create and populate a new PersonDto object.
If no matching data is found, the data reader’s Read method will throw an exception, so the
behavior is consistent with the Mock implementation, in that an exception is thrown when no
matching data is found.
Insert Operation
The insert action is managed by the DataPortal_Insert method:
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Insert()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IPersonDal>();
using (BypassPropertyChecks)
{
var data = new DataAccess.PersonDto { FirstName = FirstName, LastName = LastName };
dal.Insert(data);
Id = data.Id;
}
}
}
This method is almost identical to the one from the data reader implementation, except that the
data values come from the PersonDto object instead of individual parameters defined by the
method. And instead of returning the database-generated Id value as the result of the method, the
value is returned through the PersonDto object’s Id property.
As with the data reader implementation, the use of @@identity to get the database-generated
Id value is unqiue to SQL Server Compact Edition, and you should use SCOPE_IDENTITY with full SQL
Server.
Update Operation
The update action is managed by the DataPortal_Update method:
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Update()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IPersonDal>();
using (BypassPropertyChecks)
{
var data = new DataAccess.PersonDto { Id = Id, FirstName = FirstName, LastName = LastName };
dal.Update(data);
}
}
}
As with the Insert method, this Update method is very similar to the data reader
implementation. The only difference is that the input values are coming from the PersonDto object
instead of explicit parameters to the method.
If only deferred deletion is supported, then the call to the DAL provider’s Delete method is made
directly within the method:
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_DeleteSelf()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IPersonDal>();
using (BypassPropertyChecks)
{
dal.Delete(Id);
}
}
}
Either way, the DAL provider’s Delete method is the same as in the data reader implementation.
It gets the database connection, sets up a command object, and executes the command object to
delete the data.
Using CSLA 4: Data Access Page 113
Rev 1.0
Immediate Delete Operation
The immediate deletion implementation in EncapsulatedInvokeDto is identical to that from the
data reader solution. Please refer to that earlier discussion for information.
At this point you should understand how to implement persistence for an editable root object
using a pluggable DAL with either a data reader or DTO-based interface. The next stereotype I’ll
cover is an editable root list.
This interface defines data access actions that can be performed on the logical skill entity,
including retrieving a list of skills, a single skill, and performing insert, update, and delete actions.
The DataAccess.Mock, DataAccess.SqlCe, and DataAccess.SqlEf projects contain SkillDal
classes. Each class implements this ISkillDal interface in a different way, but with consistent
behaviors.
Each data access action includes data access invocation and data access implementation.
Because these samples are following the encapsulated invoke model, the data access invocation is
in DataPortal_XYZ or Child_XYZ methods contained in each business class. The data access
implementation is located in the Mock, SqlEf, and SqlCe DAL provider projects.
Create Operation
The create operation starts with the static factory methods in the SkillEditList class:
#if SILVERLIGHT
public static void NewSkillEditList(EventHandler<DataPortalResult<SkillEditList>> callback)
{
DataPortal.BeginCreate<SkillEditList>(callback, DataPortal.ProxyModes.LocalOnly);
}
As in the PersonEdit class, the asynchronous factory for Silverlight sets the data portal’s proxy
mode to LocalOnly so the create operation occurs on the client without relaying the call to the
application server.
The .NET factories provide asynchronous and synchronous support, relying on the RunLocal
attribute to be applied to the DataPortal_Create method to avoid calling an application server to
do the operation. The .NET DataPortal_Create method is a simple override that exists only to add
the RunLocal attribute:
[RunLocal]
protected override void DataPortal_Create()
{
base.DataPortal_Create();
}
1. Calling code creates the new child object, and adds it to the list by calling the collection’s
Add method
2. Collection implements an AddItem method that is responsible for creating the new child
object and adding it to the list
3. Calling code invokes the collection’s AddNew method, and that method creates the new child
object and adds it to the list (also used by data binding scenarios)
If you want to support techniques 1 or 2, you will need to write code to support those scenarios.
The advantage of these two techniques is that you can pass parameter values to the new child
object, and it can use those values as part of its initialization.
The SkillEdit class may implement a Child_Create method to initialize the new object. The
BusinessBase class provides a default Child_Create implementation that accepts no parameters.
That default method calls the CheckRules method to run all business rules defined for the object.
This default method is virtual, so you can override the method when necessary.
It is important to understand that the data portal’s CreateChild method can accept zero or
more parameters through a params array. The data portal will find and invoke a Child_Create
method overload that accepts the matching parameter count and types. The standard .NET method
overloading rules apply to this process.
It is also important to realize that the CreateChild method will never go across the network to
an application server. The data portal’s CreateChild and FetchChild methods invoke
Child_Create and Child_Fetch methods on the same machine where the calling code is running.
Given a NewSkillEdit method that calls the data portal’s CreateChild method, the calling code
can then add a new child to a collection like this:
var list = SkillEditList.NewSkillEditList();
var item = SkillEdit.NewSkillEdit();
list.Add(item);
If the initialization of a new child does require data access, then it must run on the application
server. This requires that a unit of work object be used to create and initialize the child. Here’s an
example of a unit of work class to create a new SkillEdit object:
[Serializable]
public class SkillEditCreator : ReadOnlyBase<SkillEditCreator>
{
public static readonly PropertyInfo<SkillEdit> ResultProperty =
RegisterProperty<SkillEdit>(c => c.Result);
public SkillEdit Result
{
get { return GetProperty(ResultProperty); }
private set { LoadProperty(ResultProperty, value); }
}
This class follows the read-only root object stereotype, and has one responsibility: create and
initialize a new SkillEdit child object. That SkillEdit object is created in the DataPortal_Fetch
method, and is returned through the Result property.
If you need to pass parameters to the new child object’s Child_Create method, you will need to
define a criteria class so you can pass those parameters through the data portal as the
SkillEditCreator object is created. Specifically, any parameters provided to the
GetSkillEditCreator method must be passed through the data portal to the DataPortal_Fetch
method using a criteria object. The DataPortal_Fetch method can then pass the parameter values
to the CreateChild method so they are available to the Child_Fetch method in the SkillEdit
class.
The calling code that wants to add a new child to the collection can now use this
SkillEditCreator to create the new child object. The calling code is different for synchronous and
asynchronous scenarios. Remember that Silverlight and WP7 can only use the asynchronous
technique.
In a synchronous scenario the calling code looks like this:
var list = SkillEditList.NewSkillEditList();
var creator = SkillEditCreator.GetSkillEditCreator();
var item = creator.Result;
list.Add(item);
It is important to remember that the asynchronous callback doesn’t run immediately. The code
in the callback lambda expression will run when the asynchronous GetSkillEditCreator method
completes. This means the application will continue to run while the new child object is created,
initialized, and returned from the server. The new child will appear in the list once it has been
returned, not instantly like in the synchronous scenario.
The AddItem method might accept parameters that are passed to the new child so it can use
those context-specific values for initialization.
You should understand that this AddItem method can be implemented synchronously or
asynchronously, and you may want to name it appropriately: BeginAddItem for asynchronous and
AddItem for synchronous. Using this naming scheme helps the calling code know what behavior to
expect when the method is invoked.
When the calling code invokes BeginAddItem it should also handle the CollectionChanged event
(or ListChanged for a BusinessBindingListBase subclass) so it is notified when the new child
object has been added to the list.
The exact same factory method and unit of work object concepts from the previous section
apply to this technique as well.
If the child object is created on the client without the need for data access, the AddItem method
will look like this:
public void AddItem()
{
Add(SkillEdit.NewSkillEdit());
}
And the NewSkillEdit factory method in the SkillEdit class will look like this:
public static SkillEdit NewSkillEdit()
{
return DataPortal.CreateChild<SkillEdit>();
}
If the child object initialization requires data access, then a unit of work object, like the
SkillEditCreator discussed in the previous section, is required. In that case the synchronous
AddItem method looks like this:
public void AddItem()
{
var creator = SkillEditCreator.GetSkillEditCreator();
Add(creator.Result);
}
As I discussed in the previous section, the data portal’s CreateChild method accepts a params
array, so you can pass in zero or more parameters. The data portal invokes a Child_Create method
overload that accepts matching parameter types based on standard .NET method overloading rules.
The new child object is created synchronously, and then it is added to the list. Finally it is
returned as the result of the method.
An override of the AddNewCore method on Silverlight or WP7 looks like this:
Using CSLA 4: Data Access Page 119
Rev 1.0
protected override void AddNewCore()
{
SkillEditCreator.GetSkillEditCreator((o, e) =>
{
if (e.Error != null)
{
throw e.Error;
}
else
{
var item = e.Object.Result;
Add(item);
OnAddedNew(item);
}
});
}
The asynchronous GetSkillEditCreator method is invoked, and when it completes the new
SkillEdit object is added to the list, and the OnAddedNew method is called to indicate that the
asynchronous operation is complete.
If you want to disable the AddNew behavior you should set the AllowNew property to false. For
example:
public SkillEditList()
{
AllowNew = false;
}
If this protected property is false, calling the AddNew method will result in an exception being
thrown.
At this point you should understand how to create new collection classes, and how to create,
initialize, and add new child items to an editable collection. I will now move on to discuss the Fetch
operation.
Fetch Operation
The Fetch operation for an editable root list starts with the static factory methods in the
SkillEditList class:
public static void GetSkillEditList(EventHandler<DataPortalResult<SkillEditList>> callback)
{
DataPortal.BeginFetch<SkillEditList>(callback);
}
#if !SILVERLIGHT
public static SkillEditList GetSkillEditList()
{
return DataPortal.Fetch<SkillEditList>();
}
#endif
These methods invoke the client-side data portal to initiate the Fetch operation. The client-side
data portal invokes the server-side data portal based on the client configuration. The server-side
data portal invokes the DataPortal_Fetch method:
private void DataPortal_Fetch()
{
var rlce = RaiseListChangedEvents;
RaiseListChangedEvents = false;
using (var dalManager = DataAccess.DalFactory.GetManager())
{
Using CSLA 4: Data Access Page 120
Rev 1.0
var dal = dalManager.GetProvider<DataAccess.ISkillDal>();
var data = dal.Fetch();
while (data.Read())
Add(DataPortal.FetchChild<SkillEdit>(data));
}
RaiseListChangedEvents = rlce;
}
Notice that the Fetch and BeginFetch methods provide no criteria parameter to the data portal,
so the data portal finds and invokes the DataPortal_Fetch overload that accepts no criteria
parameter.
This method sets the collection object’s RaiseListChangedEvents to false before loading data
into the collection, and sets it to the previous value when the method is complete. This is an
important performance optimization. As items are added to a collection the collection normally
raises a CollectionChanged event (or a ListChanged event for BusinessBindingListBase), and
that event is often handled by code that performs some work. If you load hundreds of items into a
collection that event processing can cause performance issues. Setting RaiseListChangedEvents to
false helps prevent that from occurring.
Like in the PersonEdit methods, this method uses the DalFactory class to get the DAL manager
object from the currently configured DAL provider assembly. The manager’s GetProvider method is
used to get the ISkillDal implementation, and the Fetch method is invoked to get an IDataReader
object.
The Fetch method implementation in the DataAccess.SqlCe provider looks like this:
public IDataReader Fetch()
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var cm = ctx.Connection.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,Name FROM Skill";
return cm.ExecuteReader();
}
}
This method opens a database connection and sets up a command object to retrieve the data
from the database. The command object is executed to create a data reader, and that data reader is
returned to the calling code in the DataPortal_Fetch method.
Back in the DataPortal_Fetch method, notice how the code uses a while loop to process each
item in the data reader, passing the data reader to the data portal’s FetchChild method to create
and load each child object with data. This causes the data portal to create an instance of the
SkillEdit class, and to invoke that object’s Child_Fetch method:
private void Child_Fetch(System.Data.IDataReader data)
{
using (BypassPropertyChecks)
{
Id = data.GetInt32(data.GetOrdinal("Id"));
Name = data.GetString(data.GetOrdinal("Name"));
}
}
The parameter value is a data reader that is pointing to the row of data that should be used to
load this child object’s properties. The values are copied from the data reader into the properties
Using CSLA 4: Data Access Page 121
Rev 1.0
within the using block for the BypassPropertyChecks object. This ensures that business and
authorization rules don’t run as the properties are set.
If you don’t trust the data coming from the database you should explicitly run the child object’s
business rules at the bottom of the Child_Fetch method. This is done by calling the CheckRules
method on the BusinessRules object.
Update Operation
The client-side data portal’s Update or BeginUpdate methods are called when the Save or
BeginSave method is called on an editable root list object. The client-side data portal invokes the
server-side data portal, and the server-side data portal then invokes the DataPortal_Update
method on the root business object.
A root collection class will override the DataPortal_Update method as follows:
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Update()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
base.Child_Update();
}
}
The method is marked with the Transactional attribute, so all insert, update, and delete actions
taken for each child object in the list will be considered part of a single transaction.
This code also gets the DAL manager object to be used. Remember that the DAL manager is a
disposable object that is responsible for opening or reusing a database connection. The update of
all child objects should be contained within a using block that ensures that the DAL manager or
database connection remains open throughout the process of updating all child objects.
The BusinessListBase and BusinessBindingListBase classes implement a Child_Update
method that correctly updates all child objects contained in the collection. You will not normally
need to do anything, except call this method, to cause all child objects to be updated.
The Child_Update method takes the following four steps:
4. Update (and therefore insert or update) all items in the collection itself
If you do need to implement your own update code for some rare edge case, you must follow
these three steps as well. Again, normal root collections should be able to call Child_Update as
shown in this example.
Each method retrieves the current DAL provider that implements the ISkillDal interface and
calls the appropriate DAL method to perform the data insert, update, or delete. Notice that all
interactions with the business object’s properties are within a BypassPropertyChecks block.
The SkillDal class in the SqlCe DAL provider implements these DAL methods:
public int Insert(string name)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "INSERT INTO Skill (Name) VALUES (@name)";
cm.Parameters.Add("@name", name);
cm.ExecuteNonQuery();
cm.Parameters.Clear();
cm.CommandText = "SELECT @@identity";
var r = cm.ExecuteScalar();
var newId = int.Parse(r.ToString());
return newId;
}
}
}
Each method in SkillDal is similar to the code I discussed earlier for the PersonDal class. A
database connection is opened (or reused) and a command object is initialized to perform the
appropriate action. That command object is then executed and any results are returned to the
calling code.
This method calls the client-side data portal’s Delete method, and it invokes the server-side data
portal. The server-side data portal will create an instance of the business class and will call its
DataPortal_Delete method. It is important to realize that the collection will be entirely empty at
this point, so the DataPortal_Delete method won’t interact with any data in the collection. It will
interact only with the database.
The DataPortal_Delete method will look like this:
[Transactional(TransactionalTypes.TransactionScope)]
private void DataPortal_Delete(object criteria)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
Using CSLA 4: Data Access Page 124
Rev 1.0
{
var dal = dalManager.GetProvider<DataAccess.ISkillDal>();
dal.Delete();
}
}
Notice that a Delete method is invoked on the DAL provider. The ISkillDal interface in the
sample code doesn’t define this method. To implement the immediate delete functionality, the
ISkillDal interface will need to define such a Delete method, and the DAL provider
implementations will need to implement the method.
Such a Delete method in the SqlCe provider would look like this:
public void Delete()
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "DELETE Skill";
var rowsAffected = cm.ExecuteNonQuery();
}
}
}
This method deletes all data in the Skill table, because that is the data the SkillEditList
collection would contain if it were retrieved.
As I discussed with the editable root stereotype, you should understand that a “delete”
operation doesn’t necessarily need to delete any data. Although this example does delete rows of
data from the database, you could implement the Delete method to perform an update of each
existing row to set a “deleted flag” that just marks the row as deleted.
DTO Interface
The EncapsulatedInvokeDto project contains the sample code demonstrating how to implement
persistence operations for an editable root list. The basic structure of the code is similar to the code
I just discussed for the data reader interface.
The ISkillDal interface in the DataAccess project is different because it uses DTO types instead
of data readers to pass data between the business objects and the DAL:
public interface ISkillDal
{
List<SkillDto> Fetch();
SkillDto Fetch(int id);
void Insert(SkillDto data);
void Update(SkillDto data);
void Delete(int id);
}
The SkillDto class is also in the DataAccess project, and it looks like this:
public class SkillDto
{
public int Id { get; set; }
public string Name { get; set; }
}
Create Operation
The create operation is the same with a DTO interface as in the data reader example. Please refer to
the earlier discussion for details.
Fetch Operation
The Fetch operation is similar to the data reader implementation. The DataPortal_Fetch in the
SkillEditList class is a little different because it uses the DTO type:
private void DataPortal_Fetch()
{
var rlce = RaiseListChangedEvents;
RaiseListChangedEvents = false;
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.ISkillDal>();
var data = dal.Fetch();
foreach (var item in data)
Add(DataPortal.FetchChild<SkillEdit>(item));
}
RaiseListChangedEvents = rlce;
}
Instead of getting a data reader from the DAL Fetch method, this code gets a List<SkillDto>
and it then loops through that list to create a child object for each item in the list.
The Fetch method in the SqlCe DAL provider looks like this:
public List<SkillDto> Fetch()
{
var result = new List<SkillDto>();
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var cm = ctx.Connection.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,Name FROM Skill";
using (var dr = cm.ExecuteReader())
{
while (dr.Read())
result.Add(new SkillDto { Id = dr.GetInt32(0), Name = dr.GetString(1) });
}
}
return result;
}
As in the data reader implementation, this method gets the database connection and sets up a
command object to retrieve the data. That command object is executed to get a data reader, and
the values from the data reader are used to populate the List<SkillDto> that is returned as the
result of the method.
Back in the DataPortal_Fetch method, the code loops through that list, calling the data portal’s
FetchChild method to create each child object. A SkillDto object is passed as a parameter to the
child object’s Child_Fetch method. That method is in the SkillEdit class and looks like this:
private void Child_Fetch(DataAccess.SkillDto data)
{
using (BypassPropertyChecks)
This method sets the business object’s property values from the properties in the DTO passed in
as a parameter. The property manipulation occurs in a BypassPropertyChecks block to suppress
business and authorization rules from running.
If you don’t trust the data from the database you can manually call the CheckRules method on
the BusinessRules object at the end of the Child_Fetch method.
Update Operation
The update operation is also similar to the data reader implementation. In fact, the code in
SkillEditList is identical in both cases. The code in the SkillEdit child class is a little different:
private void Child_Insert()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.ISkillDal>();
using (BypassPropertyChecks)
{
var data = new DataAccess.SkillDto { Name = Name };
dal.Insert(data);
Id = data.Id;
}
}
}
The Child_Insert and Child_Update methods create SkillDto objects and load them with data
from the business object. That DTO object is then passed as a parameter to the appropriate Insert
or Update DAL method.
The Child_Delete method is the same as in the data reader example.
The SkillDal class in the DataAccess.SqlCe project implements the DAL methods:
The code in these methods is comparable to the data reader code, except that the input values
are provided through the DTO instead of individual parameter values defined by the method. Also,
the Insert method returns the database-generated Id property through the DTO instead of
returning it as the result of the method.
This interface defines the DAL actions that can be performed on the category data entity, and it
is similar to the previous DAL interfaces you’ve seen in this chapter.
The Fetch method retrieves the data for all the root objects that will be loaded into the
collection.
Fetch Operation
The Fetch operation starts with a static factory method in the CategoryEditList collection class:
public static void GetCategoryEditList(EventHandler<DataPortalResult<CategoryEditList>> callback)
{
DataPortal.BeginFetch<CategoryEditList>(callback);
}
#if !SILVERLIGHT
public static CategoryEditList GetCategoryEditList()
{
return DataPortal.Fetch<CategoryEditList>();
}
#endif
As in the previous examples, the asynchronous factory is available to Silverlight, WP7, and .NET.
The synchronous factory is only available to .NET code.
These factory methods call the client-side data portal, and the client-side data portal invokes the
server-side data portal based on the client configuration. The server-side data portal creates an
instance of the CategoryEditList type and invokes the DataPortal_Fetch method on that object.
Zero or one criteria parameters may be passed to the data portal methods, and therefore to the
DataPortal_Fetch method. Here’s the code from the sample application:
private void DataPortal_Fetch()
{
var rlce = RaiseListChangedEvents;
RaiseListChangedEvents = false;
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.ICategoryDal>();
using (var data = dal.Fetch())
{
while (data.Read())
Add(CategoryEdit.GetCategoryEdit(
data.GetInt32(data.GetOrdinal("Id")), data.GetString(data.GetOrdinal("Category"))));
}
}
RaiseListChangedEvents = rlce;
}
This code is very similar to the editable root list implementation. It gets the data from the
database by calling the DAL Fetch method from the current DAL provider. For example, the SqlCe
provider has the following Fetch method in the CategoryDal class:
public System.Data.IDataReader Fetch()
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var cm = ctx.Connection.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,Category FROM Category";
return cm.ExecuteReader();
}
}
The results of this method are used by the DataPortal_Fetch method to populate the collection.
Using CSLA 4: Data Access Page 130
Rev 1.0
The DataPortal_Fetch method is different from the previous implementations you’ve seen, in
that the objects added to the collection are root objects. Each root object is created by invoking the
static factory method defined on the CategoryEdit class: GetCategoryEdit.
Notice that there is no factory method on the Silverlight side, because the only time a
CategoryEdit object is created is on the application server as the dynamic list is being retrieved.
The exception is that if you create a 1-tier Silverlight application you will implement this factory
method on the Silverlight side.
Also notice that the method’s scope is internal. This is because the method should only be
invoked by the DataPortal_Fetch method of the dynamic list.
Finally, you can see that this isn’t a typical root factory method, because it accepts numerous
parameters and uses those values to set the properties of the business object.
The business object is created by calling the data portal’s Fetch method, but in a dynamic root
class the DataPortal_Fetch method typically does no work. Here’s that method in the
CategoryEdit class:
private void DataPortal_Fetch()
{}
The result of the GetCategoryEdit factory method is a root object populated with data from the
database, where that data was provided by the DataPortal_Fetch method of the dynamic list
parent object.
In summary, the static factory method in the collection class invokes the data portal’s Fetch or
BeginFetch method to retrieve the list. The data portal invokes the collection object’s
DataPortal_Fetch method, and that method gets the data from the DAL provider. Each row of data
from the database is used to create a dynamic root object, and that object is added to the list.
Update Operation
The update operation in a dynamic list is quite different from the update in an editable root list. In a
dynamic list, the update operation is usually automatically triggered by data binding when the user
moves off the current row in a datagrid control, or deletes a row in a datagrid control.
You can also force the update of an individual root object in the list by calling the SaveItem
method on the collection:
list.SaveItem(item);
Because the update operation is always asynchronous, the dynamic list stereotype is
not well suited to web application development. If you do use a dynamic list in a
web application, you will need to implement thread synchronization code to ensure
the update completes before the page or service code completes.
When the user moves off a row in a datagrid control, or deletes a row in a datagrid control, or
you directly invoke the SaveItem method, one dynamic root object contained in the dynamic list is
updated. The dynamic list base class will invoke the BeginSave method of the root object, causing
that root object to be saved through the data portal.
When BeginSave is called on a root object, the BeginSave method calls the client-side data
portal’s BeginUpdate method. That causes the server-side data portal to invoke the root object’s
DataPortal_Insert, DataPortal_Update, or DataPortal_DeleteSelf method depending on the
metastate of the object. This is exactly the same as with any editable root object, and I’ve already
discussed this process in detail with the PersonEdit business type.
If you look in the sample code at the CategoryEdit class you will find the three DataPortal_XYZ
methods that invoke the data access behaviors. Each of these methods gets the current DAL
provider object and invokes the Insert, Update, or Delete DAL method to perform the appropriate
data access action.
The result is that the data for the individual dynamic root object is persisted.
DTO Interface
The EncapsulatedInvokeDto solution contains an implementation of a dynamic list using a data
reader based interface. The DataAccess project includes the ICategoryDal interface:
public interface ICategoryDal
{
List<CategoryDto> Fetch();
void Insert(CategoryDto data);
void Update(CategoryDto data);
void Delete(int id);
}
This interface defines the DAL actions that can be performed on the category data entity, using a
DTO instead of a data reader and explicit method parameter values. The CategoryDto contains the
values that need to flow between the business object and the data access code:
public class CategoryDto
{
public int Id { get; set; }
public string Category { get; set; }
}
Fetch Operation
The factory methods for the Fetch operation are the same in the DTO example as they were in the
data reader example. The CategoryEditList class also contains the DataPortal_Fetch method,
and this method is a little different with a DTO-based DAL interface:
private void DataPortal_Fetch()
{
var rlce = RaiseListChangedEvents;
RaiseListChangedEvents = false;
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.ICategoryDal>();
var data = dal.Fetch();
foreach (var item in data)
Add(CategoryEdit.GetCategoryEdit(item));
}
RaiseListChangedEvents = rlce;
}
The DAL provider’s Fetch method returns a List<CategoryDto>, and the data in that list is used
to create and populate each dynamic root object that is added to the collection. The Fetch method
in the SqlCe provider looks like this:
public List<CategoryDto> Fetch()
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var result = new List<CategoryDto>();
var cm = ctx.Connection.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,Category FROM Category";
using (var dr = cm.ExecuteReader())
{
while (dr.Read())
{
result.Add(new CategoryDto { Id = dr.GetInt32(0), Category = dr.GetString(1) });
}
}
return result;
}
}
The result of this method is used by the DataPortal_Fetch method to create individual dynamic
root objects. Each root object is created by calling the static factory method in the CategoryEdit
class:
internal static CategoryEdit GetCategoryEdit(DataAccess.CategoryDto data)
{
var result = DataPortal.Fetch<CategoryEdit>();
using (result.BypassPropertyChecks)
{
result.Id = data.Id;
result.Name = data.Category;
}
return result;
}
Using CSLA 4: Data Access Page 133
Rev 1.0
Notice how the factory method accepts a parameter of type CategoryDto, allowing the parent’s
DataPortal_Fetch method to pass in each row of data to create the root objects.
The factory method creates a new instance of the root object using the data portal as I discussed
in the data reader implementation. Then that object’s properties are loaded with data from the
DTO parameter.
The result is a fully populated dynamic list object containing dynamic root objects.
Update Operation
The update operation works the same with a DTO interface as with the data reader interface. As
you can imagine, the DataPortal_XYZ methods and DAL methods that implement the insert,
update, and delete actions use CategoryDto objects to pass data between the business object code
and the DAL provider code.
I’ve already discussed the update process for an editable root object with the PersonEdit class
and the data reader implementation of the CategoryEdit class.
You can look at the CategoryEdit class in the EncapsulatedInvokeDto solution to see the DTO-
based DataPortal_XYZ methods, and you can look at the CategoryDal classes in the DAL provider
projects to see how the insert, update, and delete actions are implemented.
The line item person entity represents a link table that links a row in the OrderLineItems table
to a row in the Persons table. This link table could contain other metadata about the relationship
beween the line item and person, but for this example the table contains two columns, and
therefore the entity contains only those two values as well.
You can see how the Fetch method requires the lineItemId parameter so it retrieves data for a
specific line item.
I’ll walk through each persistence operation for the object graph. I will focus more on the
process flow, and less on the specific DAL code, because the DAL provider code that implements
each of the DAL interfaces is essentially the same as the DAL code you’ve seen in every example so
far.
Create Operation
The create operation starts with the static factory methods in the root OrderEdit class:
#if SILVERLIGHT
public static void NewOrderEdit(int customerId, EventHandler<DataPortalResult<OrderEdit>> callback)
{
DataPortal.BeginCreate<OrderEdit>(customerId, callback, DataPortal.ProxyModes.LocalOnly);
}
#else
public static void NewOrderEdit(int customerId, EventHandler<DataPortalResult<OrderEdit>> callback)
{
DataPortal.BeginCreate<OrderEdit>(customerId, callback);
}
These factory methods are slightly different from the previous examples, because they require a
parameter value. When an order is created, it is created for a specific customer, and the
customerId parameter ensures that the customer is identified before the order is created.
The DataPortal_Create method accepts this value as a parameter. Here’s the Silverlight
implementation:
protected void DataPortal_Create(
int customerId, Csla.DataPortalClient.LocalProxy<OrderEdit>.CompletedHandler handler)
{
using (BypassPropertyChecks)
{
Using CSLA 4: Data Access Page 136
Rev 1.0
Id = -1;
CustomerId = customerId;
OrderDate = DateTime.Today;
LastEdit = DateTime.Today;
}
OrderLineItems = DataPortal.CreateChild<OrderLineItems>();
base.DataPortal_Create(handler);
}
Remember that the Silverlight method is potentially asynchronous, and when it is complete the
callback handler must be invoked. Even though this specific implementation is not async, the
handler still must be called. The base implementation of DataPortal_Create is invoked, because it
properly invokes the callback handler.
This Silverlight implementation is required because the Silverlight factory method uses the
LocalOnly proxy mode, ensuring that the object graph is created on the client, not on the
application server.
The .NET implementation uses the RunLocal attribute to achieve the same goal:
[RunLocal]
protected void DataPortal_Create(int customerId)
{
using (BypassPropertyChecks)
{
Id = -1;
CustomerId = customerId;
OrderDate = DateTime.Today;
LastEdit = DateTime.Today;
}
OrderLineItems = DataPortal.CreateChild<OrderLineItems>();
base.DataPortal_Create();
}
In both implementations, notice how the OrderEdit object’s properties are initialized, including
setting the CustomerId property to the value of the customerId parameter.
Also notice how both implementations call the data portal’s CreateChild method to create an
instance of the OrderLineItems child collection. This causes the data portal to invoke the
Child_Create method in the OrderLineItems class. If you look at that class you won’t find such a
method, because the base implementation in the BusinessListBase class is sufficient, and there’s
typically no need to override that method.
The result of this process is that an OrderEdit root object, containing an empty OrderLineItems
collection, is created and initialized.
This method initializes the new object’s properties, including the Persons property that contains
an OrderLinePersons child collection object. The data portal’s CreateChild method is used to
create an instance of this new child collection. Again, I rely on the Child_Create implementation in
the BusinessListBase class to initialize the new collection object.
You can also use the other two techniques I discussed for adding child items to an editable
collection earlier in this chapter. See the discussion around adding SkillEdit child objects to the
SkillEditList collection for more information about the Add and AddItem method techniques.
Fetch Operation
The Fetch operation is more interesting, because it typically requires multiple database interactions
to load the entire object graph. As I mentioned earlier, you typically need to make a database call
for each major level in the object graph hierarchy.
There are some technologies that can help you “avoid” multiple database interactions, including
the use of the ADO.NET Entity Framework or the DataSet object. It is important to recognize that in
most cases these technologies still do multiple database interactions. They just do the interactions
behind the scenes so you don’t explicitly see them. What looks to you like one database interaction
is one logical database interaction, possibly consisting of numerous calls to the database.
The data reader interface makes each database interaction explicit, and that gives you an
opportunity to see and optimize each interaction.
The Fetch operation starts with the static factory methods in the OrderEdit class:
public static void GetOrderEdit(int id, EventHandler<DataPortalResult<OrderEdit>> callback)
{
DataPortal.BeginFetch<OrderEdit>(id, callback);
}
#if !SILVERLIGHT
public static OrderEdit GetOrderEdit(int id)
{
return DataPortal.Fetch<OrderEdit>(id);
}
#endif
By now this type of code should be familiar. The method gets the DAL provider and calls the
Fetch method to get a data reader that contains the data necessary to populate the OrderEdit
object. I won’t show the Fetch method from the OrderDal class, because you’ve seen several Fetch
methods at this point.
The FetchChild method is called to create and populate the OrderLineItems child collection
with child OrderLineItem objects. The code in the example passes the order id parameter value to
the FetchChild method, so the Child_Fetch method in the OrderLineItems class can retrieve the
child data:
#if !SILVERLIGHT
private void Child_Fetch(int orderId)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IOrderLineItemDal>();
var data = dal.Fetch(orderId);
var rlce = RaiseListChangedEvents;
RaiseListChangedEvents = false;
while (data.Read())
Add(DataPortal.FetchChild<OrderLineItem>(data));
RaiseListChangedEvents = rlce;
}
}
#endif
This method gets the DAL provider implementation for the IOrderLineItemDal interface, and
calls its Fetch method to get a data reader with the data. This code is essentially identical to the
code used to load the SkillEditList collection with data earlier in this chapter.
As you have probably guessed, the OrderLineItem class contains a Child_Fetch that loads the
child object with data from the data reader:
private void Child_Fetch(System.Data.IDataReader data)
{
using (BypassPropertyChecks)
{
Id = data.GetInt32(data.GetOrdinal("Id"));
var shipDateIndex = data.GetOrdinal("ShipDate");
if (!data.IsDBNull(shipDateIndex))
Using CSLA 4: Data Access Page 139
Rev 1.0
ShipDate = data.GetDateTime(shipDateIndex);
Persons = DataPortal.FetchChild<OrderLinePersons>(Id);
}
}
This method also creates and populates the OrderLinePersons child collection by calling the
data portal’s FetchChild method. The line item’s Id property is passed as a parameter to the
FetchChild method, and therefore to the Child_Fetch method implemented in the
OrderLinePersons class.
At this point the process repeats. The collection’s Child_Fetch method retrieves the data
necessary to populate the child OrderLinePerson objects by invoking the DAL provider:
private void Child_Fetch(int lineItemId)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IOrderLineItemPersonDal>();
var data = dal.Fetch(lineItemId);
var rlce = RaiseListChangedEvents;
RaiseListChangedEvents = false;
while (data.Read())
Add(DataPortal.FetchChild<OrderLinePerson>(data));
RaiseListChangedEvents = rlce;
}
}
The data portal’s FetchChild method is used to create and populate each individual
OrderLinePerson object based on the data in the data reader. The Child_Fetch method in the
OrderLinePerson class looks like this:
private void Child_Fetch(System.Data.IDataReader data)
{
using (BypassPropertyChecks)
{
LineItemId = data.GetInt32(data.GetOrdinal("LineItemId"));
PersonId = data.GetInt32(data.GetOrdinal("PersonId"));
}
}
The database interaction occurs at each major level of the object graph: OrderEdit,
OrderLineItems, and OrderLinePersons.
Notice that the query field contains two SELECT statements. The first SELECT retrieves the data
for the OrderEdit object, and the second retrieves the data for the child OrderLineItem objects.
The resulting data reader will read through the data from the first SELECT statement, and then
through the data from the second statement. It is important to remember that data readers are
linear: they read through data sequentially.
The DataPortal_Fetch method in the OrderEdit class must also be changed to accommodate
the multiple results in a single data reader:
private void DataPortal_Fetch(int id)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IOrderDal>();
var data = dal.Fetch(id);
data.Read();
using (BypassPropertyChecks)
{
Id = data.GetInt32(data.GetOrdinal("Id"));
CustomerId = data.GetInt32(data.GetOrdinal("CustomerId"));
OrderDate = data.GetDateTime(data.GetOrdinal("OrderDate"));
LastEdit = data.GetDateTime(data.GetOrdinal("OrderEditDate"));
}
data.NextResult();
OrderLineItems = DataPortal.FetchChild<OrderLineItems>(data);
}
}
After the data for the OrderEdit object is read from the data reader, the data reader’s
NextResult method is called to move the data reader to the results of the second SELECT
statement.
Notice that this change to DataPortal_Fetch means that this implementation is incompatible
with the existing SqlEf, SqlCe and Mock implementations, or with implementations for other
databases that don’t support multiple queries in a single database command.
This fundamentally changes the expected behavior of the DAL implementations. You
need to take this into consideration, because all DAL providers must conform to the
same set of expected behaviors so they remain interchangeable.
This new implementation no longer calls its own Fetch method from the OrderLineItemDal
provider, because it already has an open data reader containing the data it needs to create and
populate its child objects.
This data reader contains the exact same data as the OrderLineItemDal provider’s Fetch
method provided. The code in the OrderLineItem, OrderLinePersons, and OrderLinePerson
classes are unaffected.
At this point you should understand how to fetch a root object, its child objects, and grandchild
objects by using a data reader based DAL interface. I will now walk through the process of updating
data from a complex object graph.
Update Operation
The Update operation is straightforward compared to the Fetch operation.
Each data entity has a DAL provider interface: IOrderDal, IOrderLineItemDal, and
IOrderLineItemPersonDal.
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Update()
{
The code to interact with the OrderDal DAL provider should be nothing new at this point.
The FieldManager property is a protected method from the BusinessBase class, and it provides
access to the metadata maintained about the business object’s properties. The field manager is
aware of all child properties, assuming you’ve declared them using the techniques discussed in the
Using CSLA 4: Creating Business Objects ebook.
The field manager’s UpdateChildren method loops through all properties that reference child
objects, calling the data portal’s UpdateChild method on each child object. In the sample
application, the only child object contained in an OrderEdit object is the OrderLineItems child
collection.
All child properties are updated. If your object contains more than one child property, the
UpdateChild method will loop through every child property to call the data portal’s UpdateChild
method. The order in which child objects are updated is indeterminate. If you need one child object
to update before another child object you will need to update each child explicitly.
For example, instead of calling the field manager’s UpdateChildren method, the
DataPortal_Insert and DataPortal_Update code could do this:
//FieldManager.UpdateChildren(this);
DataPortal.UpdateChild(OrderLineItems, this);
By explicitly updating each child object, you can control the order in which the updates occur.
The field manager’s UpdateChildren method and the explicit data portal UpdateChild method
both accept zero or more parameters that will be passed to the child object’s Child_Update
method.
If the child object is a collection, the data portal will only invoke a Child_Update
method. If the child object is an editable child object, the data portal will
automatically invoke a Child_Insert, Child_Update, or Child_DeleteSelf method
depending on the IsNew and IsDelete metastate property values of the child object.
It is very common for a parent object to pass this as a parameter, so the child object has access
to the parent’s properties during the update process. Most child objects require the parent object’s
Id property (or other property values) as foreign keys that must be provided to the database.
4. Update (and therefore insert or update) all items in the collection itself
The parameter value passed to the collection’s Child_Update method is automatically passed to
each child object in the collection by the default implementation in the CSLA .NET base classes. This
means the Child_Insert, Child_Update, and Child_DeleteSelf methods in the OrderLineItem
class must accept a parameter of type OrderEdit so their method signatures match the provided
parameter types:
private void Child_Insert(OrderEdit order)
{
using (BypassPropertyChecks)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IOrderLineItemDal>();
using (BypassPropertyChecks)
{
Id = dal.Insert(order.Id, ShipDate);
}
FieldManager.UpdateChildren(this);
}
}
}
Notice how the order parameter’s Id property value is supplied to the DAL methods so the
database has access to the correct foreign key value to perform each insert, update, and delete
action.
Also notice how the Child_Insert and Child_Update methods call the field manager’s
UpdateChildren method to update the grandchild objects. I won’t show the code in the
OrderLinePerson class, because it is a repeat of what you’ve now seen several times in this chapter.
The end result is that the OrderEdit root object updates the database, and then cascades the
insert, update, and delete actions through its children. The child objects cascade the operation
through its children.
Delete Operation
In the update operation discussion, I focused primarily on the insert and update actions. This is
because there are several ways to approach the deletion of the entire object graph, or child and
grandchild data within a complex object graph.
All of these are valid options, though the use of cascade delete or stored procedures does
require that your database support those features. You can always implement the delete
operations in your DAL provider, even if your data store isn’t a relational database, or if your
database doesn’t support cascading deletes or stored procedures.
[Transactional(TransactionalTypes.TransactionScope)]
private void DataPortal_Delete(int id)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IOrderDal>();
dal.Delete(id);
// cascading delete removed all data, so recreate child collection
OrderLineItems = DataPortal.CreateChild<OrderLineItems>();
}
}
Notice the call to the DAL provider’s Delete method. This method deletes all data for the entire
object graph. I’ll walk through that method in a moment.
Before covering the DAL code itself, I want to point out the line of code that sets the
OrderLineItems property to a new child collection by calling the data portal’s CreateChild
method. This is important, because it ensures that the object graph in memory reflects the data in
the database.
Because the DAL provider’s Delete method removed all data for this object graph in the
database, the current OrderEdit object no longer has any child data in the database. This means
that whatever data was in the child collection is invalid. The simplest way to get the object graph in
sync with the state of the database is to ensure that the OrderEdit object contains an empty child
collection.
Creating a new child collection removes any reference to the previous child
collection. This means that the OrderEdit object no longer has any child or
grandchild objects.
The SqlCe DAL provider implementation of the Delete method is found in the OrderDal class:
public void Delete(int id)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var lineItemDal = DataAccess.DalFactory.GetManager().GetProvider<IOrderLineItemDal>();
lineItemDal.DeleteAllForOrder(id);
You can see how this method creates a command object and uses it to delete the data from the
Order table. Before it does this, however, it invokes the DeleteAllForOrder method from the
IOrderLineItemDal implementation:
var lineItemDal = DataAccess.DalFactory.GetManager().GetProvider<IOrderLineItemDal>();
lineItemDal.DeleteAllForOrder(id);
It is necessary to remove the child data in the database before removing the data in the parent
table, otherwise there’d be a violation of relational integrity. The OrderDal code could have directly
deleted the data OrderLineItems table data, but it is better to keep all data access actions for a
logical data entity within that entity’s DAL implementation.
The OrderLineItemDal class contains the DeleteAllForOrder method. This method is a little
more complex, because it performs three steps:
2. Loop through the line item id values to delete the LineItemPersons table data for each line
item
There are various ways to implement these steps. My goal in this code is not to optimize the
process, but to explicitly show the steps so they are easy to understand. In a real application you
will probably optimize the process to meet your needs. Here’s the DeleteAllForOrder method:
public void DeleteAllForOrder(int orderId)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
// make a copy of all the line item id values
var lineItemIds = new List<int>();
using (var lineItems = Fetch(orderId))
{
while (lineItems.Read())
lineItemIds.Add(lineItems.GetInt32(0));
}
Any time an object is removed from an editable list, the child object’s IsDeleted
property is set to true, and the object is moved to the collection’s DeletedList.
When the collection is updated, the first step in the collection’s Child_Update method is to
“update” all items in the DeletedList. Because every object in the DeletedList has an IsDeleted
value of true, the data portal will invoke that child object’s Child_DeleteSelf method.
The OrderLineItem child class has a Child_DeleteSelf method:
private void Child_DeleteSelf(OrderEdit order)
{
using (BypassPropertyChecks)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
Because an OrderLineItem object may contain child objects, it calls the field manager’s
UpdateChildren method to update its children before updating itself. This ensures that any pending
data operations in its OrderLinePerson child objects occur before the line item data is deleted.
You might wonder why this is important, but remember that a “delete” operation doesn’t always
delete the data. Sometimes a “deleting” data means setting a column value in a table to “inactive”
or “deleted” and the data isn’t physically removed. Because of this, it is important to ensure all data
updates occur to keep the object graph and database in sync.
Once all the data has been updated and/or deleted, the OrderLineItem object’s Persons
property is reset to an empty collection. This ensures that the object graph in memory matches the
state of the database, because a deleted line item obviously can’t have any child data.
The Delete method in the IOrderLineItemDal provider is responsible for deleting the line item
data, and any child data for the line item. The SqlCe provider implementation looks like this:
public void Delete(int lineItemId)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
// delete OrderLineItemPersons data
var lineItemPersonDal =
DataAccess.DalFactory.GetManager().GetProvider<IOrderLineItemPersonDal>();
lineItemPersonDal.DeleteAllForLineItem(lineItemId);
This method invokes the same DeleteAllForLineItem method I discussed earlier, ensuring that
all child data in the OrderLineItemPersons is deleted before the line item row is deleted.
The OrderLinePerson class also has a Child_DeleteSelf method:
private void Child_DeleteSelf(OrderLineItem lineItem)
{
using (BypassPropertyChecks)
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IOrderLineItemPersonDal>();
dal.Delete(LineItemId, PersonId);
}
}
}
As you can see, deleting an individual child object is straightforward. Deleting an object with
children is more complex, because the application must ensure that the data for that object, and its
child objects, are properly deleted.
DTO Interface
The overall process and code structure is the same for a DTO-based interface as for the data reader
interface. I won’t repeat the walkthrough of the code.
Each parent create operation is responsible for initializing the properties of the parent object,
including properties that refer to child objects. This means the create operation for the parent also
creates the child. Similarly, the create of a child causes the creation of any grandchild objects.
The Fetch operation for a root object retrieves that object’s data, including its child objects. The
DAL provider is invoked by the root object’s DataPortal_Fetch method, and each child implements
a Child_Fetch method to load the child data. If there are grandchild objects, their data is typically
retrieved with individual database calls, and the objects are loaded with data in Child_Fetch
methods.
When a root object is saved, the data portal’s Update or BeginUpdate method is invoked,
resulting in a call to a DataPortal_XYZ method on the root object. If the root object is an editable
root, the data portal will invoke DataPortal_Insert, DataPortal_Update, or
DataPortal_DeleteSelf based on the metastate of the root object. If the root object is an editable
list, the data portal will call the object’s DataPortal_Update method. Each editable child and
grandchild object will implement Child_Insert, Child_Update, and Child_DeleteSelf methods to
interact with the DAL provider to perform the correct data action. Each editable child list may
override the Child_Update method, but the implementation in the BusinessListBase and
BusinessBindingListBase classes are usually sufficient.
In each case, the DataPortal_XYZ and Child_XYZ methods invoke the DAL provider to interact
with the database, typically passing DTO objects into the DAL methods.
When immediate deletion is implemented by a root object, the data portal’s Delete or
BeginDelete method is invoked, resulting in a call to the DataPortal_Delete method. This method
is responsible for deleting the root object’s data, along with any child data.
Using CSLA 4: Data Access Page 150
Rev 1.0
Remember that a “delete” operation may or may not delete data in the database. Instead of
deleting data, the delete implementation in a DAL provider might mark rows as “inactive” or
“deleted” by setting a column value.
Again, you can review the code in the EncapsulatedInvokeDto project and compare it to the
EncapsulatedInvoke project. You’ll see that the structure of the DAL interfaces is the same, the
methods just return and accept DTO types instead of IDataReader and primitive parameters.
The primary value of the DTO approach over the IDataReader approach is that there’s a higher
level of abstraction because the DAL interface is not coupled to ADO.NET in any way. The primary
drawbacks are that this approach requires more code, and adds some overhead as data is copied
into and out of the DTO objects as it flows between the Business and Data Access layers.
At this point you should understand how a complex object graph consisting of root, child, and
grandchild objects is persisted using the encapsulated invoke data portal model.
You’ve seen this interface earlier in this chapter. In this case I am focusing on the ShipOrder
method. This method will be implemented by each DAL provider to perform the data access
necessary to ship an order.
The DataPortal_Execute method in the OrderShipper class will invoke this method. As I
mentioned earlier, the DataPortal_Execute method does not have to invoke the DAL at all. It might
invoke a server-side workflow, update some files, invoke a service, or perform other actions. In fact,
it could do all of those actions if that is necessary to implement the behavior of the command.
The DataAccess.Mock, DataAccess.SqlCe, and DataAccess.SqlEf projects contain the OrderDal
classes I discussed earlier. Each class implements this ShipOrder method in a manner appropriate
for the specific data access technology supported by the provider.
Execute Operation
The execute operation starts with the client calling the Ship method in the OrderShipper class:
public static void Ship(int orderId, EventHandler<DataPortalResult<OrderShipper>> callback)
{
var cmd = new OrderShipper(orderId);
DataPortal.BeginExecute<OrderShipper>(cmd, callback);
}
#if !SILVERLIGHT
public static OrderShipper Ship(int orderId)
{
var cmd = new OrderShipper(orderId);
return DataPortal.Execute<OrderShipper>(cmd);
}
#endif
There are two overloads of the Ship method, one synchronous and the other asynchronous.
These are essentially static factory methods, but instead of retrieving an editable or read-only
object, they invoke the data portal’s Execute or BeginExecute method to execute the command.
Notice that the first thing these methods do is to create and initialize an instance of the
OrderShipper command. If the OrderShipper object needed to do some work before going to the
server, these factory methods would interact with the object prior to calling the data portal’s
Execute or BeginExecute method.
Similarly, if the OrderShipper object needed to do some work after coming back from the
server, these factory methods would interact with the object returned from the data portal to
perform that work.
The client-side data portal invokes the server-side data portal based on the client configuration.
The server-side data portal calls the DataPortal_Execute method in the OrderShipper object:
protected override void DataPortal_Execute()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IOrderDal>();
ShippingNumber = dal.ShipOrder(OrderId);
}
}
The SqlCe and SqlEf implementations wrap the code in a using block to ensure the same
database connection or EF object context is appropriately reused by the entire series of data access
actions.
The ShipOrder method calls the Update method of the OrderDal class to update the order with a
new OrderEditDate value:
public void Update(int id, DateTime? lastDate)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "UPDATE [Order] SET OrderEditDate=@orderEditDate WHERE Id=@id";
cm.Parameters.Add("@id", id);
cm.Parameters.Add("@orderEditDate", lastDate);
var rowsAffected = cm.ExecuteNonQuery();
if (rowsAffected == 0)
throw new DataNotFoundException("Order");
}
}
}
The ShipOrder method then loops through the line items for the order, updating the ShipDate
of each line item by calling the existing Update method implemented in the IOrderLineItemDal
implementation. It even uses the existing Fetch method to get the list of line items.
Although there are other ways to write this code that might be more efficient, I am using this
code to illustrate how a command implementation can leverage existing code to perform
comparatively complex actions.
DTO Interface
The DataAccess project in the EncapsulatednvokeDto solution includes the IOrderDal interface,
with a definition for the ShipOrder method:
Using CSLA 4: Data Access Page 153
Rev 1.0
public interface IOrderDal
{
int ShipOrder(int id);
OrderDto Fetch(int id);
void Insert(OrderDto data);
void Update(OrderDto data);
void Delete(int id);
}
This method signature is the same as in the data reader implementation, but the
implementation of this method in each DAL provider will be DTO-based.
Execute Operation
The execute operation follows the same general flow as with the data reader implementation. The
OrderShipper class implements Ship methods that invoke the data portal’s Execute or
BeginExecute methods. The client-side data portal calls the server-side data portal, and the server-
side data portal invokes the command object’s DataPortal_Execute method.
The DataPortal_Execute method is identical to the one in the data reader implementation,
because the ShipOrder method signature is also identical.
The ShipOrder method implementation in each DAL provider is different, because it makes use
of the existing DTO-based methods implemented in each project. For example, this is the
implementation in the DataAccess.SqlEf project:
public int ShipOrder(int id)
{
using (var ctx = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities"))
{
// ship order and generate shipping number
var order = Fetch(id);
order.OrderEditDate = DateTime.Today;
Update(order);
The existing Fetch method in the OrderDal class is used to retrieve an OrderDto, and then the
Update method is used to update the order data with a new OrderEditDate value.
The order’s line items are then retrieved by using the IOrderLineItemDal implementation, and
each line item’s ShipDate value is updated.
All of this work is done within a using block to ensure that the same database connection or
object context is reused by the various data access actions.
At this point you should understand how the DataPortal_Execute method of a command object
is invoked by the server-side data portal. This method might interact with the DAL provider as
shown in these examples, or it might perform other actions such as running a workflow or
interacting with other server-side resources.
Using CSLA 4: Data Access Page 154
Rev 1.0
Unit of Work Object Persistence
In the Using CSLA 4: Creating Business Objects ebook I discussed the concept of a unit of work
object. There are two basic types of unit of work:
1. Retrieving objects
2. Updating objects
Perhaps the most common scenario is to use a unit of work object that retrieves other objects.
In many applications it is necessary to retrieve multiple objects to correctly populate a UI or
implement an algorithm. It can be difficult to ensure that all necessary objects are available at the
same time when you are using the asynchronous data portal. Because Silverlight and WP7
applications must use the asynchronous data portal, and because WPF applications often use it to
maintain a responsive UI, it is important to understand how to implement this type of unit of work
object.
A unit of work object that performs object retrieval is typically implemented as a subclass of the
ReadOnlyBase class. This type of unit of work is a special case of a read-only object, where the
properties of the unit of work object are instances of other business objects. I’ll walk through an
example of this type of unit of work later in this section.
A less common scenario is where multiple editable root objects must be updated as part of a
single server call. Typically this is because these root objects need to be updated within the context
of a single database transaction, and as the result of a single user gesture, such as the user clicking a
Save button.
A unit of work object that performs an update of objects is implemented as a command object.
In this case the command object’s properties are instances of the editable root objects that are to
be saved.
In most cases there is no specific data access or persistence code for a unit of work object.
Instead, the unit of work object will make use of the existing synchronous factory methods
implemented by the objects being retrieved, or the synchronous Save method on the editable root
objects being updated.
Because of this, there is no difference in implementation between the data reader and DTO-
based implementations of any unit of work types.
Retreiving Objects
The PersonEditUoW class in the Library.Net projects of the EncapsulatedInvoke and
EncapsulatedInvokeDto solutions. This class implements a read-only object stereotype, with
properties that contain other business objects:
[Serializable]
public class PersonEditUoW : ReadOnlyBase<PersonEditUoW>
{
public static readonly PropertyInfo<PersonEdit> PersonEditProperty =
RegisterProperty<PersonEdit>(c => c.PersonEdit);
public PersonEdit PersonEdit
{
get { return GetProperty(PersonEditProperty); }
#if !SILVERLIGHT
public static PersonEditUoW GetPersonEditUoW(int personId)
{
return DataPortal.Fetch<PersonEditUoW>(personId);
}
The important thing to recognize is that this is a normal read-only implementation. It has
synchronous and asynchronous static factory methods that return an instance of the
PersonEditUoW type.
That resulting object has PersonEdit and CategoryList properties, each of which provide
access to a business object. You might write UI code like this:
var uow = PersonEditUoW.GetPersonEditUoW(personId);
var personEdit = uow.PersonEdit;
var categoryList = uow.CategoryList;
The result is that the UI code can guarantee that it has access to both the PersonEdit and
CategoryList objects at the same time, even if the server call is asynchronous. Here’s the UI code
with an asynchronous call:
PersonEdit person = null;
CategoryList catList = null;
var uow = PersonEditUoW.GetPersonEditUoW(personId, (o, e) =>
{
if (e.Error != null)
throw e.Error;
person = e.Object.PersonEdit;
catList = e.Object.CategoryList;
});
In many cases this can be critically important, because data binding may require both objects at
the same time to properly bind and render the UI.
Back in the PersonEditUoW class, the most interesting part of the code is the DataPortal_Fetch
method that runs on the server:
private void DataPortal_Fetch(int personId)
{
Using CSLA 4: Data Access Page 156
Rev 1.0
PersonEdit = PersonEdit.GetPersonEdit(personId);
CategoryList = CategoryList.GetCategoryList();
}
This method doesn’t invoke any DAL directly. Instead, it calls the existing synchronous static
factory methods already implemented by the PersonEdit and CategoryList classes.
Those factory methods invoke the “client-side” data portal. Because the code is already running
on the server, the “client-side” data portal is running on the server. When the client-side data portal
invokes the server-side data portal, it does so locally, without crossing any network boundary. This
is because the code is already running on the server, and the data portal configuration on the
application server is to run locally.
The server-side data portal invokes the DataPortal_Fetch methods on the PersonEdit and
CategoryList objects as normal. Those methods act no differently when invoked from the UI or
from another business object.
The result is that the unit of work object’s properties contain the two business objects. When
the unit of work object is returned to the client through the data portal, the calling code will have
access to those objects.
Updating Objects
The PersonsUpdater class in the Library.Net project is a command object that updates two
PersonEdit objects as a unit of work. Both PersonEdit objects are updated as part of the same
database transaction, so if either update fails they are both rolled back.
Here’s the code for the unit of work command class:
[Serializable]
public class PersonsUpdater : CommandBase<PersonsUpdater>
{
public static readonly PropertyInfo<PersonEdit> Person1Property =
RegisterProperty<PersonEdit>(c => c.Person1);
public PersonEdit Person1
{
get { return ReadProperty(Person1Property); }
private set { LoadProperty(Person1Property, value); }
}
#if !SILVERLIGHT
public static PersonsUpdater Update(PersonEdit person1, PersonEdit person2)
{
var cmd = new PersonsUpdater { Person1 = person1, Person2 = person2 };
return DataPortal.Execute<PersonsUpdater>(cmd);
}
Using CSLA 4: Data Access Page 157
Rev 1.0
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Execute()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
Person1 = Person1.Save();
Person2 = Person2.Save();
}
}
#endif
}
As with any command stereotype implementation, this class defines properties for the values
that flow from the client to the server, and then back to the client. In this case the properties each
contain a PersonEdit object.
The static factory methods create an instance of the PersonsUpdater class, and then execute
that command by invoking the data portal’s Execute or BeginExecute method.
The most interesting part of the code is the DataPortal_Execute method:
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Execute()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
Person1 = Person1.Save();
Person2 = Person2.Save();
}
}
Notice how the Transactional attribute is used to ensure that a TransactionScope object is
created before this method is invoked. This means that all actions taken within this method are
protected by a transaction.
Also, it is important to note the using block for the DalManager object that wraps all the work
done in this method. This ensures that a database connection or object context is kept open for
reuse as both PersonEdit objects are saved.
Each PersonEdit object is saved with a call to its synchronous Save method. The Save method
invokes the “client-side” data portal’s Update method. Because the code is already running on the
server, the client-side data portal is running on the server. When the client-side data portal invokes
the server-side data portal, it does so locally, without crossing any network boundary. This is
because the code is already running on the server, and the data portal configuration on the
application server is to run locally.
The server-side data portal invokes the appropriate DataPortal_XYZ method of the PersonEdit
object to perform the insert, update, or delete operation. This is based on the business object’s
metastate. I described this process earlier in this chapter when I discussed persistence of an
editable object.
At this point you should understand how unit of work objects are implemented for retrieving
and updating objects.
The Fetch method returns an IDataReader instance that contains person data from the
database. This data can be used to populate the PersonList read-only collection.
Fetch Operation
The Fetch operation starts in the static factory method of the PersonList class:
public static void GetPersonList(EventHandler<DataPortalResult<PersonList>> callback)
{
DataPortal.BeginFetch<PersonList>(callback);
}
#if !SILVERLIGHT
public static PersonList GetPersonList()
{
return DataPortal.Fetch<PersonList>();
}
#endif
As you should expect, there are synchronous and asynchronous factory methods that invoke the
data portal’s Fetch and BeginFetch methods. As with any other object stereotype, the data portal
ultimately invokes the DataPortal_Fetch method on the PersonList object:
private void DataPortal_Fetch()
{
IsReadOnly = false;
var rlce = RaiseListChangedEvents;
RaiseListChangedEvents = false;
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IPersonDal>();
using (var data = dal.Fetch())
while (data.Read())
{
var item = DataPortal.FetchChild<PersonInfo>(data);
Add(item);
}
Because this object is a read-only list, items can not normally be added or removed from the
collection. To “unlock” the collection, the IsReadOnly property must be set to false. The setter for
this property is protected, so code outside the business class can’t change the value.
Once the collection’s IsReadOnly property is set to false, loading the collection with data is
done in exactly the same manner as in an editable root list. The RaiseListChangedEvents property
is set to false, the data is retrieved by invoking the DAL, and the data portal’s FetchChild method
is used to create and load objects that are added to the list.
Each DAL provider implements the Fetch method defined by the IPersonDal interface in its
PersonDal class. For example, the SqlEf provider’s implementation looks like this:
public System.Data.IDataReader Fetch()
{
using (var ctx = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities"))
{
var data = from r in ctx.ObjectContext.People
select r;
return new ListDataReader<Person>(data);
}
}
The data is retrieved from the database using an EF query, and the results of that query are
wrapped in a ListDataReader so they are available as an IDataReader object.
The SqlCe provider implementation is more direct:
public System.Data.IDataReader Fetch()
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var cm = ctx.Connection.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,FirstName,LastName FROM Person";
return cm.ExecuteReader();
}
}
This implementation executes a SELECT command against the database and returns the resulting
data reader object.
Back in the PersonList class, the DataPortal_Fetch method loops through the results of the
DAL Fetch method, calling the data portal’s FetchChild method to create and load each child
object with data from the data reader. This causes the data portal to invoke the Child_Fetch
method defined in the PersonInfo class:
#if !SILVERLIGHT
private void Child_Fetch(System.Data.IDataReader data)
{
Id = data.GetInt32(data.GetOrdinal("Id"));
Name = string.Format("{0} {1}",
data.GetString(data.GetOrdinal("FirstName")),
data.GetString(data.GetOrdinal("LastName")));
}
#endif
The property getter uses the GetProperty helper method, so this operation is subject to normal
authorization rules.
The setter is private in scope, and uses the LoadProperty helper method. This makes the
property read-only, so the value can only be changed by code in the PropertyInfo object, and it
means that no business, validation, or authorization rules are run as the property value is changed.
The end result is that the PersonList object is loaded with PersonInfo objects, and then the
IsReadOnly property is set back to true so the collection can’t be changed.
DTO Interface
The EncapsulatedInvokeDto solutions’s DataAccess project defines the IPersonDal interface:
public interface IPersonDal
{
List<PersonDto> Fetch();
PersonDto Fetch(int id);
void Insert(PersonDto data);
void Update(PersonDto data);
void Delete(int id);
}
As with the data reader implementation, this interface defines a Fetch method that returns a
List<PersonDto> object, and that data can be used to populate a read-only PersonList collection.
Fetch Operation
The overall flow of the Fetch operation is the same for a DTO-based model as for the data reader
model. The DataPortalFetch method in the PersonList class is slightly different, because it creates
the child objects using data from the List<T> instead of a data reader:
private void DataPortal_Fetch()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.IPersonDal>();
var data = dal.Fetch();
IsReadOnly = false;
var rlce = RaiseListChangedEvents;
RaiseListChangedEvents = false;
foreach (var item in data)
Add(DataPortal.FetchChild<PersonInfo>(item));
RaiseListChangedEvents = true;
IsReadOnly = true;
Using CSLA 4: Data Access Page 161
Rev 1.0
}
}
This method loads the business object’s properties with the data from the DTO.
The Fetch method implementation in each DAL provider is different as well. For example, the
SqlCe provider’s PersonDal class has this code:
public List<PersonDto> Fetch()
{
var result = new List<PersonDto>();
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var cm = ctx.Connection.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,FirstName,LastName FROM Person";
using (var dr = cm.ExecuteReader())
{
while (dr.Read())
result.Add(new PersonDto
{ Id = dr.GetInt32(0), FirstName = dr.GetString(1), LastName = dr.GetString(2) });
}
}
return result;
}
The data is retrieved from the database, and is then used to create the List<PersonDto>
collection that is returned as a result.
The Fetch method is used to populate the CategoryList name-value list object. Each DAL
provider implements this method, returning a data reader with the category data needed to
populate the business object.
Fetch Operation
The Fetch operation starts with the typical static factory methods in the CategoryList class:
public static void GetCategoryList(EventHandler<DataPortalResult<CategoryList>> callback)
{
DataPortal.BeginFetch<CategoryList>(callback);
}
#if !SILVERLIGHT
public static CategoryList GetCategoryList()
{
return DataPortal.Fetch<CategoryList>();
}
#endif
Based ont this code, the data portal invokes the DataPortal_Fetch method on the
CategoryList object:
private void DataPortal_Fetch()
{
using (var dalManager = DataAccess.DalFactory.GetManager())
{
var dal = dalManager.GetProvider<DataAccess.ICategoryDal>();
using (var data = dal.Fetch())
{
IsReadOnly = false;
var rlce = RaiseListChangedEvents;
RaiseListChangedEvents = false;
while (data.Read())
{
Add(new NameValuePair(
data.GetInt32(data.GetOrdinal("Id")), data.GetString(data.GetOrdinal("Category"))));
}
RaiseListChangedEvents = rlce;
IsReadOnly = true;
}
}
}
Because a name-value list is a read-only list, the IsReadOnly property must be set to false to
“unlock” the list, and then set back to true after the collection has been loaded with data.
As with any collection object, the RaiseListChangedEvents is set to false and then restored to
its original value after the data load is complete.
The business object is of type NameValueListBase<K, V>. The NameValueListBase class defines
a NameValuePair to have a Key property of type K and a Value property of type V. In this case, the
CategoryList is of type NameValueListBase<int, string> , so the Key property is type int, and
the Value property is type string.
Having this pre-defined NameValuePair type simplifies the code necessary to create a name-
value list, because your code can simply use this existing type, loading each object with data and
adding it to the collection.
The Fetch method in each DAL provider is different, but is responsible for returning a valid data
reader. For example, the SqlEf implementation looks like this:
public System.Data.IDataReader Fetch()
{
using (var ctx = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities"))
{
var data = from r in ctx.ObjectContext.CategoryTables
select r;
return new ListDataReader<CategoryTable>(data);
}
}
An EF query is used to retrieve the data, and the results of that query are wrapping in an object
that implements the IDataReader interface to conform to the requirements of the ICategoryDal
interface.
DTO Interface
The DataAccess project in the EncapsulatedInvokeDto defines an ICategoryDal interface for the
category data entity:
public interface ICategoryDal
{
List<CategoryDto> Fetch();
void Insert(CategoryDto data);
void Update(CategoryDto data);
void Delete(int id);
}
It also defines the CategoryDto type returned in a list from the Fetch method:
public class CategoryDto
{
public int Id { get; set; }
public string Category { get; set; }
}
These types are used to implement the CategoryList class’s DataPortal_Fetch and DAL
provider code in the solution.
And the DTO type is used to create the list returned from each DAL provider. For example, the
SqlEf implementation looks like this:
public List<CategoryDto> Fetch()
{
using (var ctx = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities"))
{
var data = from r in ctx.ObjectContext.CategoryTables
select new CategoryDto { Id = r.Id, Category = r.Category };
return data.ToList();
}
}
The data is retrieved using an EF query that generates a list of CategoryDto objects. That list is
returned as a result from the Fetch method.
At this point you should understand how to implement the Fetch operations for a read-only list
and a name-value list.
In this chapter I walked through each business object stereotype, demonstrating how to use the
encapsulated invoke data portal model to implement persistence for each stereotype. In the next
chapter I will walk through the same stereotypes, showing how to implement persistence using the
factory implementation data portal model.
The default factory loader used by CSLA .NET (if you don’t specify your own) uses the factory
name value from each ObjectFactory attribute on a business class as an assembly qualified type
for the object factory type. For example, a business class might have the following attribute:
[Csla.Server.ObjectFactory("DataAccess.SqlCe.PersonDal,DataAccess.SqlCe")]
[Serializable]
public class PersonEdit : BusinessBase<PersonEdit>
In 1- or 2-tier physical deployments the DAL assemblies must also be on the client
workstation, because the “server-side” data portal components will run on the
client.
It is important to understand that the RunLocal attribute and ProxyMode.LocalOnly options will
not work if the DAL assemblies are only deployed to the server in a 3- or 4-tier deployment. The
object factory for every business class will include the create operation implementation, and if the
object factory is only deployed to the application server, then all object creation must occur on the
application server.
The business classes will not implement DataPortal_XYZ or Child_XYZ methods when using a
factory implementation or factory invocation data portal model. This is because the data access is
handled by the object factories.
A custom factory loader is used to combine the “PersonDal” value with application configuration
information to determine the assembly and full type name of the object factory type.
A custom factory loader is a class that implements the IObjectFactoryLoader interface from the
Csla.Server namespace. Here’s the interface definition:
public interface IObjectFactoryLoader
{
Type GetFactoryType(string factoryName);
object GetFactory(string factoryName);
}
The GetFactoryType method returns the Type object for the object factory type based on the
object factory name parameter from an ObjectFactory attribute.
The GetFactory method returns an instance of the object factory type. Usually the GetFactory
method will call the GetFactoryType method to get the Type object, and will then use the .NET
Framework’s Activator type to create an instance of that type.
The FactoryImplementation solution includes a DataAccess project. That project contains a
FactoryLoader class:
public class FactoryLoader : Csla.Server.IObjectFactoryLoader
{
public string Assembly { get; set; }
public FactoryLoader()
{
Assembly = ConfigurationManager.AppSettings["ObjectFactoryAssembly"];
}
The object’s constructor retrieves the ObjectFactoryAssembly value from the app.config or
web.config file. The expectation is that this value will contain the name of the assembly that
contains the concrete DAL implementation. For example:
<appSettings>
<add key="ObjectFactoryAssembly" value="DataAccess.Mock"/>
<!--<add key="ObjectFactoryAssembly" value="DataAccess.SqlCe"/>-->
<!--<add key="ObjectFactoryAssembly" value="DataAccess.SqlEf"/>-->
<add key="CslaObjectFactoryLoader" value="DataAccess.FactoryLoader,DataAccess"/>
</appSettings>
Looking at the code in the FactoryLoader class, you can see how the GetFactoryType
implementation combines the factoryName parameter value with the assembly name from the
config file to create an assembly qualified type name. The assembly name is also used as the
namespace for the object factory type:
var typeName = string.Format("{0}.{1},{0}", Assembly, factoryName);
The GetType method from the .NET Framework’s Type class is then used to dynamically get a
Type object corresponding to this type name, and that value is returned as a result of the method.
The GetFactory method is comparatively simple, because it simply invokes the standard .NET
CreateInstance method to create an instance of the type returned from the GetFactoryType
method.
Although this custom factory loader is simple, it is effective and can meet the needs of many
applications. If your application has more complex requirements, such as loading the object factory
objects using an IoC framework, your custom factory implementation may be quite different.
At this point you should understand how a custom factory loader is implemented such that it
returns the Type object for an object factory type, or an instance of that type. The factory loader is
invoked by the server-side data portal when the data portal needs an object factory type or
instance to do its work.
I will now walk through each business object stereotype, describing how to implement
persistence using the factory implementation data portal model.
The requirements for an object factory class are minimal. The default factory loader, as well as
the custom factory loader implemented in the FactoryImplementation solution, requires only the
following:
If you have created your own factory loader, you may impose different restrictions on object
factory types.
The reason the PersonDal classes inherit from the ObjectFactory base class is to gain access to
the protected methods ObjectFactory provides. You will see those protected methods used
throughout the code as each data portal operation is implemented.
I’ll start with the create operation.
Create Operation
The create operation starts with the NewPersonEdit factory methods in the PersonEdit class:
public static void NewPersonEdit(EventHandler<DataPortalResult<PersonEdit>> callback)
{
DataPortal.BeginCreate<PersonEdit>(callback);
}
#if !SILVERLIGHT
public static PersonEdit NewPersonEdit()
{
return DataPortal.Create<PersonEdit>();
}
#endif
The client-side data portal invokes the server-side data portal based on the client configuration.
Because the PersonEdit class has an ObjectFactory attribute, the server-side data portal uses
the factory loader to get an instance of the PersonDal object factory. The data portal then invokes
the Create method on that factory object, and it returns the result of the Create method to the
client.
Notice that the static factory methods call the data portal’s Create and BeginCreate methods,
passing no criteria parameter. As a result, the data portal invokes a matching Create method with
no criteria parameter on the factory object.
If a criteria parameter is passed to the data portal’s Create or BeginCreate methods, the data
portal will invoke a Create method on the factory object with a matching parameter type. You may
have multiple Create method overloads in the object factory class, and they will be invoked as
appropriate based on the type of parameter passed to the data portal on the client.
The object factory’s Create method implements the following steps:
3. Mark the business object as new (setting IsNew and IsDirty to true)
Notice that this factory method is completely responsible for creating the object, setting its state,
and its metastate, and returning the object as a result. This is completely unlike the encapsulated
invoke or encapsulated implementation models, where the data portal creates the business object
and manages its metastate automatically.
The result of this method is a new PersonEdit business object that has default values in its
properties, and the correct metastate.
Fetch Operation
The fetch action starts with the GetPersonEdit factory methods in the PersonEdit class:
public static void GetPersonEdit(int id, EventHandler<DataPortalResult<PersonEdit>> callback)
{
DataPortal.BeginFetch<PersonEdit>(id, callback);
}
#if !SILVERLIGHT
public static PersonEdit GetPersonEdit(int id)
{
return DataPortal.Fetch<PersonEdit>(id);
}
#endif
Using CSLA 4: Data Access Page 171
Rev 1.0
These methods invoke the client-side data portal to create an instance of the business class and
load that object with pre-existing data from the database. The client-side data portal invokes the
server-side data portal based on the client configuration. The server-side data portal then asks the
factory loader to create an instance of the object factory defined by the ObjectFactory attribute on
the PersonEdit business class. The data portal invokes the Fetch method on that factory object.
Notice that the static factory methods call the data portal’s Fetch and BeginFetch methods,
passing an int criteria parameter. As a result, the data portal invokes a matching Fetch method
with an int criteria parameter on the factory object.
If a different (or no) criteria parameter is passed to the data portal’s Fetch and BeginFetch
methods, the data portal will invoke a Fetch method on the factory object with a matching
parameter type. You may have multiple Fetch method overloads in the object factory class, and
they will be invoked as appropriate based on the type of parameter passed to the data portal on the
client.
The factory object’s Fetch method is responsible for the following:
3. Load the business object’s properties with values from the database
4. Mark the business object as old (setting IsNew and IsDirty to false)
5. Optionally invoke all business and validation rules on the business object
Each DAL implementation performs step 2 differently, but otherwise every implementation is
consistent.
Mock Implementation
The DataAccess.Mock implementation uses the mock database:
public PersonEdit Fetch(int id)
{
var result = new PersonEdit();
var data = MockDb.MockDb.Persons.Where(r => r.Id == id).First();
using (BypassPropertyChecks(result))
{
LoadProperty(result, PersonEdit.IdProperty, data.Id);
result.FirstName = data.FirstName;
result.LastName = data.LastName;
}
MarkOld(result);
return result;
}
The code that accesses the business object’s properties is within a using block for the object’s
BypassPropertyChecks object. This suppresses rule checking during the process, and ensures that
no business, validation, or authorization rules will run as the object is loaded with data.
The same steps are followed, but an ObjectContextManager is used to create or reuse the EF
object context, and therefore the underlying database connection. That EF ObjectContext is then
used for the EF query to get the data from the database based on the criteria parameter.
The data from the EF entity is then used to load the business object’s property values, the
MarkOld method is used to set the business object’s metastate, and the business object is returned
as a result.
ADO.NET Implementation
Finally, the SqlCe implementation uses an ADO.NET database query to get the data:
public PersonEdit Fetch(int id)
{
var result = new PersonEdit();
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,FirstName,LastName FROM Person WHERE Id=@id";
cm.Parameters.Add("@id", id);
using (var dr = cm.ExecuteReader())
{
var idIndex = dr.GetOrdinal("Id");
var firstIndex = dr.GetOrdinal("FirstName");
var lastIndex = dr.GetOrdinal("LastName");
dr.Read();
using (BypassPropertyChecks(result))
{
LoadProperty(result, PersonEdit.IdProperty, dr.GetInt32(dr.GetOrdinal("Id")));
result.FirstName = dr.GetString(dr.GetOrdinal("FirstName"));
result.LastName = dr.GetString(dr.GetOrdinal("LastName"));
}
}
}
}
MarkOld(result);
return result;
}
Update Operation
When an editable root object is saved, the Save or BeginSave method invokes the client-side data
portal by calling its Update or BeginUpdate method. That client-side method invokes the server-side
data portal based on the client configuration, and the server-side data portal uses the factory
loader to get an instance of the appropriate factory object based on the ObjectFactory attribute
on the PersonEdit business class.
The data portal then invokes the Update method on the factory object, passing the business
object as a parameter to the Update method. Because database updates are bi-directional, the
Update method must return the business object as a result.
Within your Update method implementation, you need to use the business object’s IsNew and
IsDeleted metastate properties to determine whether to perform an insert, update, or delete
action. In all three concrete DAL implementations, the Update method in the PersonDal class looks
the same:
[Csla.Transactional(Csla.TransactionalTypes.TransactionScope)]
public PersonEdit Update(PersonEdit obj)
{
if (obj.IsDeleted)
{
if (!obj.IsNew)
using (BypassPropertyChecks(obj))
Delete(obj.Id);
MarkNew(obj);
}
else if (obj.IsNew)
{
using (BypassPropertyChecks(obj))
{
var newId = InsertPerson(obj.FirstName, obj.LastName);
LoadProperty(obj, PersonEdit.IdProperty, newId);
}
MarkOld(obj);
}
else if (obj.IsDirty)
{
using (BypassPropertyChecks(obj))
{
UpdatePerson(obj.Id, obj.FirstName, obj.LastName);
}
MarkOld(obj);
}
return obj;
}
Delete Action
The delete action occurs if the business object’s IsDeleted property is true.
If the business object’s IsNew property is false, then we have a reasonable expectation that the
object corresponds to data in the database. In that case a Delete method is invoked to delete the
data:
if (obj.IsDeleted)
{
if (!obj.IsNew)
using (BypassPropertyChecks(obj))
Delete(obj.Id);
MarkNew(obj);
}
The immediate delete operation (discussed later) also requires a Delete method in the
PersonDal class, and I’m simply reusing that existing method. Here’s the Delete method from the
SqlCe implementation:
[Csla.Transactional(Csla.TransactionalTypes.TransactionScope)]
public void Delete(int id)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "DELETE Person WHERE Id=@id";
cm.Parameters.Add("@id", id);
var rowsAffected = cm.ExecuteNonQuery();
if (rowsAffected == 0)
throw new InvalidOperationException("Zero rows deleted");
}
}
}
Although this method has the Transactional attribute, in this specific scenario it is not being
invoked by the data portal, and so the attribute is not used and has no effect on the method. This
code is already running within a transaction because of the Transactional attribute on the Update
method of the PersonDal class; a method that was invoked by the data portal.
The Delete method creates a command object for the DELETE query, and executes the command
to delete the data.
Back in the Update method, it is important to notice that the MarkNew method is called to set the
business object’s metastate so IsNew and IsDirty are true, and IsDeleted is false. Because the
business object no longer corresponds to a row of data in the database, and because the object’s
properties no longer match values in the database, the object is both new and changed.
The InsertPerson method is a private method in the PersonDal class. Notice that this method
returns the new database-generated Id property value for the data, and that value is placed into
the business object’s Id property.
The call to the MarkOld method is also important. The MarkOld method sets the object’s IsNew
and IsDirty properties to false.
Now that the business object’s data has been inserted into the database, there is a reasonable
expectation that the object corresponds to a row of data so it is no longer new. Additionally, there
is a reasonable expectation that the object’s properties match values in the database, so it is no
longer dirty or changed.
The InsertPerson method is different for each DAL implementation. For example, the SqlEf
implementation looks like this:
private int InsertPerson(string firstName, string lastName)
{
using (var ctx = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities"))
{
var data = new Person { FirstName = firstName, LastName = lastName };
ctx.ObjectContext.AddToPeople(data);
var count = ctx.ObjectContext.SaveChanges();
if (count == 0)
throw new InvalidOperationException("PersonDal.Insert");
return data.Id;
}
}
This is standard EF code, where a Person entity object is created, and the business object’s
property values are used to populate the entity object’s properties. The entity object is then added
to the EF ObjectContext object’s People collection and the changes are committed to the database
by calling the SaveChanges method.
Once the changes have been committed, the database-generated Id property is automatically
placed back into the Person entity object, so that value can be returned as a result of the
InsertPerson method.
Update Action
The update action occurs if the business object isn’t marked for deletion and isn’t new. In this case
the business object’s data needs to be updated into the database. This is done by calling an
UpdatePerson method from the PersonDal class’s Update method:
As an optimization, this code only runs if the business object has been changed. If the IsDirty
property is false, the object hasn’t been changed so there is nothing to update.
The code that accesses the business object’s properties is within a using block for the object’s
BypassPropertyChecks object. This suppresses rule checking during the process, and avoids
authorization rule violations.
The call to the MarkOld method is also important. The MarkOld method sets the object’s IsNew
and IsDirty properties to false.
The UpdatePerson method is different in each concrete DAL implementation. The SqlCe
implementation, for example, looks like this:
private void UpdatePerson(int id, string firstName, string lastName)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "UPDATE Person SET FirstName=@firstName,LastName=@lastName WHERE Id=@id";
cm.Parameters.Add("@id", id);
cm.Parameters.Add("@firstName", firstName);
cm.Parameters.Add("@lastName", lastName);
var rowsAffected = cm.ExecuteNonQuery();
if (rowsAffected == 0)
throw new InvalidOperationException("Zero rows updated");
}
}
}
A command object is created and loaded with parameter values corresponding to the business
object’s property values. The command is then executed to perform the UPDATE query in the
database.
You can see how the object factory’s Update method uses the business object’s metastate to
determine whether to perform a delete, insert, or update action. Each of those actions is
implemented differently depending on the type of data access technology being used, but they all
perform the same steps, and interact with the business object’s properties and metastate in a
consistent manner.
This method basically invokes the same DAL provider Delete method I discussed from the
update operation when IsDeleted is true. In this case, however, the Delete method is invoked
directly by the data portal, so the Transactional attribute is important. Based on this attribute, the
data portal ensures that the code is running within a TransactionScope object before the Delete
method is invoked.
Because this method is implemented using EF, it retrieves the Person entity from the database,
deletes it from the ObjectContext object, and saves the changes to the context by calling the
SaveChanges method. The result is that the data is deleted from the database.
At this point you should understand how to implement persistence for an editable root object
with a factory object, including the Create, Fetch, Update, and immediate Delete operations.
The custom factory loader will combine the “SkillDal” parameter value with the application
configuration information to create an assembly qualified type name for the object factory type.
Each of the three concrete DAL projects implements a SkillDal class.
Create Operation
The create operation works the same with an editable root list as for an editable root object. The
business class implements static factory methods that call the data portal, and the data portal
relays the call to the server.
Collections don’t have metadata that can be affected by methods such as MarkNew or MarkOld, so
there’s no need to try and set metadata on the new business object. The metadata of a collection is
calculated based on the metadata of the child objects it contains.
1. Calling code creates the new child object, and adds it to the list by calling the collection’s
Add method
2. Collection implements an AddItem method that is responsible for creating the new child
object and adding it to the list
3. Calling code invokes the collection’s AddNew method, and that method creates the new child
object and adds it to the list (also used by data binding scenarios)
As I discussed in Chapter 5, each of these options requires or allows you to write the code that
creates the child object.
Because the factory-based data portal models generally require that all DAL code run on the
server, you should consider whether creating a child object needs data access or other server-side
resources.
#if SILVERLIGHT
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public override void Child_Create()
#else
protected override void Child_Create()
The static factory method calls the data portal’s CreateChild method to create an instance of
the child object. The CreateChild method always runs synchronously, and doesn’t go across the
network to an application server, so it runs local to where it was invoked.
The scope of the Child_Create method must be different on Silverlight due to limitations on
reflection and dynamic method invocation, otherwise the method is the same on .NET, Silverlight,
and WP7.
The result of this code is that any of the three options for creating and adding a new child object
to the collection can use this static factory method to create and initialize an instance of the child
type.
The ObjectFactory attribute indicates that the data portal should use the SkillDal object
factory type, and that the Fetch operation should cause the object factory’s CreateSkill method to
be invoked, instead of the default Fetch method.
As you can imagine, each of the SkillDal classes in the concrete DAL implementations includes
a CreateSkill method. That method is responsible for creating and returning a SkillEditCreator
object.
Because the sample FactoryImplemetation solution doesn’t actually talk to the database to
create a SkillEdit object, the CreateSkill methods in all three DAL providers is the same:
public SkillEditCreator CreateSkill()
{
var result = new SkillEditCreator();
var newChild = new SkillEdit();
MarkAsChild(newChild);
MarkNew(newChild);
LoadProperty(result, SkillEditCreator.ResultProperty, newChild);
return result;
}
This code creates the SkillEditCreator object that will be returned as a result.
In a real application the new SkillEdit child would be initialized with default values loaded
from the database.
The new SkillEdit child object is then loaded into the SkillEditCreator object’s Result
property, and the SkillEditCreator is returned as a result.
The result of this effort is that any of the three options for creating and adding a new child
object to the SkillEditList collection can use the SkillEditCreator to get a new child object
using code like this:
var creator = SkillEditCreator.GetSkillEditCreator();
var newChild = creator.Result;
Or in an asynchronous setting, such as Silverlight, the code would look like this:
SkillEdit newChild = null;
SkillEditCreator.GetSkillEditCreator((o, e) =>
{
if (e.Error != null)
throw e.Error;
newChild = e.Object.Result;
});
Once the calling code has the new child object, that object can be added to the collection using
one of the three options I discussed in Chapter 5.
Fetch Operation
The Fetch operation for an editable root list works much like the fetch for an editable object. The
business class implements static factory methods, and they invoke the client-side data portal. The
client-side data portal invokes the server-side data portal, and it uses the factory loader to load an
instance of the correct object factory type based on the ObjectFactory attribute on the business
class.
The data portal then invokes the Fetch method on the factory object. In the case of an editable
root list, that Fetch method is responsible for the following:
4. Create an instance of the SkillEdit child object for each row of data
5. Mark each child object as old (setting IsNew and IsDirty to false)
6. Optionally invoke all business and validation rules on each child business object
As you can see, the Fetch method is responsible for not only creating the collection it will return
as a result, but it is also responsible for creating and loading each child object’s state and metastate.
Each DAL implementation is somewhat different, based on the data access technology being
used. But they each follow the same steps.
Mock Implementation
The Mock implementation retrieves its data from the mock database:
public SkillEditList Fetch()
{
var result = new SkillEditList();
result.RaiseListChangedEvents = false;
var data = MockDb.MockDb.Skills;
foreach (var item in data)
{
var child = new SkillEdit();
MarkAsChild(child);
MarkOld(child);
LoadProperty(child, SkillEdit.IdProperty, item.Id);
LoadProperty(child, SkillEdit.NameProperty, item.Name);
result.Add(child);
}
result.RaiseListChangedEvents = true;
return result;
}
You can see how the method creates the SkillEditList object and sets its
RaiseListChangedEvents property.
The method then retrieves the data from the mock database, and loops through each row of
data to create and populate SkillEdit child objects. The MarkAsChild and MarkOld methods are
called on each child object to set the metastate.
Finally the fully populated collection is returned as a result of the method, and the data portal
returns it to the client.
An EF ObjectContext object is used to access the database, and an EF query is run to select the
data. The code then loops through each row of data to create and populate the SkillEdit child
objects.
ADO.NET Implementation
The ADO.NET implementation is in the DataAccess.SqlCe project, and the SkillDal class contains
this Fetch method:
public SkillEditList Fetch()
{
var result = new SkillEditList();
result.RaiseListChangedEvents = false;
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var cm = ctx.Connection.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,Name FROM Skill";
using (var dr = cm.ExecuteReader())
{
while (dr.Read())
{
var child = new SkillEdit();
MarkAsChild(child);
MarkOld(child);
LoadProperty(child, SkillEdit.IdProperty, dr.GetInt32(0));
LoadProperty(child, SkillEdit.NameProperty, dr.GetString(1));
result.Add(child);
}
}
}
result.RaiseListChangedEvents = true;
return result;
}
The same steps are followed in this method, the only difference being in the way the data is
retrieved from the database.
Update Operation
When an editable root list is saved by calling its Save or BeginSave method, the client-side data
portal’s Update or BeginUpdate method is invoked. This results in a call to the server-side data
portal, which gets an object factory instance from the factory loader based on the ObjectFactory
attribute on the business class.
The server-side data portal then invokes the Update method of the factory object, passing the
collection as a parameter. Because update operations are bi-directional, the Update method also
returns the business object as a result so it can be returned to the client with any changes that
occurred to the business objects on the server.
When persisting an editable root list, the Update method implements the following steps:
I usually isolate the update of child items into a separate private method. In the SkillDal classes
you’ll find an UpdateSkillEdit method that updates the individual child items. By isolating this
code, the Update method itself is the same in all three DAL implementations:
[Csla.Transactional(Csla.TransactionalTypes.TransactionScope)]
public SkillEditList Update(SkillEditList obj)
{
obj.RaiseListChangedEvents = false;
foreach (var item in GetDeletedList<SkillEdit>(obj))
UpdateSkillEdit(item);
GetDeletedList<SkillEdit>(obj).Clear();
foreach (var item in obj)
UpdateSkillEdit(item);
obj.RaiseListChangedEvents = true;
return obj;
}
The only exception is that the Mock implementation doesn’t use the Transactional attribute
because it doesn’t interact with a real database.
The UpdateSkillEdit method is responsible for updating each editable child object. Updating an
editable child object is the same as updating an editable root object, in that the object’s metastate
is used to determine whether to perform a delete, insert, or update action.
Again, I isolate each data action into a separate method, so the UpdateSkillEdit method is the
same in all three DAL implementations:
private void UpdateSkillEdit(SkillEdit obj)
{
if (obj.IsDeleted)
{
if (!obj.IsNew)
using (BypassPropertyChecks(obj))
DeleteSkill(obj.Id);
MarkNew(obj);
}
else if (obj.IsNew)
{
using (BypassPropertyChecks(obj))
{
var newId = InsertSkill(obj.Name);
LoadProperty(obj, SkillEdit.IdProperty, newId);
}
MarkOld(obj);
}
else if (obj.IsDirty)
{
using (BypassPropertyChecks(obj))
{
UpdateSkill(obj.Id, obj.Name);
}
Using CSLA 4: Data Access Page 184
Rev 1.0
MarkOld(obj);
}
}
If you compare this method to the Update method in the PersonDal class, you will see that the
flow of the logic is the same. This same logical flow should be used to update any editable root or
child object.
As you can imagine, the DeleteSkill, InsertSkill, and UpdateSkill methods are different for
each DAL provider based on the type of data access technology being used. The code in these
methods is comparable to the methods in the PersonDal class, so I won’t walk through them in
detail.
The result of the Update method in the SkillDal class is that the child objects in the collection’s
DeletedList are deleted, and the child objects in the collection itself are inserted or updated based
on their individual metastate.
This method uses a command object to delete all records from the Skill table, and therefore
from the SkillEditList collection.
At this point you should understand how to implement the Create, Fetch, Update, and
immediate Delete operations for an editable root list. And you should see how the same techniques
for creating and adding child objects to a collection from Chapter 5 apply in a factory-based data
portal model.
With these attributes in place, the data portal will now invoke methods on the CategoryDal class
to perform the data portal operations.
Fetch Operation
When a dynamic list is retrieved, it is loaded with the editable root objects it contains. Although
each editable root object could load itself from the database, it is more efficient to retrieve all the
data as a single query, and to then use that data to populate the editable root objects.
This process is very similar to the Fetch operation for an editable root list, except that the
MarkAsChild method isn’t called to mark the “child” objects as children.
For example, here’s the FetchEditList method from the SqlEf implementation of the
CategoryDal class:
public CategoryEditList FetchEditList()
{
var result = new CategoryEditList();
var rlce = result.RaiseListChangedEvents;
result.RaiseListChangedEvents = false;
using (var ctx = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities"))
{
var data = from r in ctx.ObjectContext.CategoryTables
select r;
foreach (var item in data)
{
var edit = new CategoryEdit();
using (BypassPropertyChecks(edit))
This method creates the new CategoryEditList collection and sets its RaiseListChangedEvents
property to false. It then executes an EF query to get data from the database.
Once it has the data, the method loops through each row of data, and it creates a CategoryEdit
object for that row. The data is used to load the properties of the CategoryEdit object, and the
MarkOld method is called to set the object’s metastate.
Notice that MarkAsChild is not called. The CategoryEdit object is an editable root object, not a
child.
Once all the CategoryEdit editable root objects have been loaded and added to the collection,
the CategoryEditList collection is returned as a result.
Update Operation
As the user interacts with the editable root objects in the dynamic list, the CategoryEditList
object will automatically save each root object. As I discuss in the Using CSLA 4: Creating Business
Objects ebook, the save of each root object is typically triggered by data binding events. The
DynamicListBase and DynamicBindingListBase classes are implemented so they react properly in
smart client data binding scenarios where the collection is bound to a datagrid control that raises
the correct data binding events.
When an individual CategoryEdit editable root object is saved, its BeginSave method is called.
That results in a call to the client-side data portal’s BeginUpdate method. The client-side data portal
invokes the server-side data portal, which then uses the factory loader to get an instance of the
appropriate object factory type.
The data portal then calls the Update method on the factory object, passing the CategoryEdit
editable root object to the method as a parameter. Because updates are bi-directional, the Update
method also returns the business object as a result.
Because CategoryEdit is an editable root object, the code to implement its Update method, and
corresponding delete, insert, and update actions, is the same as for the PersonEdit and SkillEdit
classes I’ve already discussed. I won’t repeat that content here, you can look at the three
CategoryEdit classes to see how they implement the Update method.
At this point you should understand how to use the factory implementation data portal model
for persistence of an editable root object, an editable root list with editable child objects, and a
dynamic list containing root objects. Next, I will discuss persisting a more editable complex object
graph.
The child classes do not have an ObjectFactory attribute, because they are never directly
persisted using the data portal.
Create Operation
The create operation for the OrderEdit editable root object is implemented in a Create method of
the OrderDal classes in each of the DAL projects. Because the sample application doesn’t interact
with the database to create the OrderEdit object or its child objects, the Create methods are the
same in each DAL implementation:
public OrderEdit Create(int customerId)
{
var result = new OrderEdit();
MarkNew(result);
LoadProperty(result, OrderEdit.IdProperty, -1);
LoadProperty(result, OrderEdit.CustomerIdProperty, customerId);
LoadProperty(result, OrderEdit.OrderDateProperty, DateTime.Today);
LoadProperty(result, OrderEdit.OrderEditProperty, DateTime.Today);
var old = new OrderLineItemDal();
LoadProperty(result, OrderEdit.OrderLineItemsProperty, old.CreateList());
return result;
}
This method follows the same steps I outlined for the PersonEdit create operation. The only
meaningful difference is that the OrderLineItemDal is used to create an instance of the
OrderLineItems editable child list:
var old = new OrderLineItemDal();
LoadProperty(result, OrderEdit.OrderLineItemsProperty, old.CreateList());
The CreateList method in the OrderLineItemsDal class is responsible for creating a new child
list object:
public OrderLineItems CreateList()
{
var result = new OrderLineItems();
MarkAsChild(result);
return result;
}
The method signatures for Silverlight and .NET are different due to Silverlight limitations on
reflection and dynamic method invocation. Otherwise the implementations are the same.
#if SILVERLIGHT
[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
public void Child_Create(int personId)
#else
private void Child_Create(int personId)
#endif
{
using (BypassPropertyChecks)
{
LineItemId = -1;
I discussed this technique earlier in this chapter when I covered creating new child objects for
the SkillEditList editable collection, and also in Chapter 5.
Fetch Operation
The Fetch operation for an OrderEdit editable root object is the same as for any editable root
object. The OrderEdit class implements static factory methods that invoke the data portal, and the
data portal ultimately calls the Fetch method on the appropriate OrderDal factory object.
An EF ObjectContext object is used to access the database, and an EF query is run to retrieve
the root object’s data. The data values in the entity object returned from the query are used to
populate the properties of the OrderEdit business object.
This code is in the using block for the ObjectContextManager, ensuring that the same database
connection will be reused to retrieve the child object data.
In the OrderLineItemDal class, the FetchList method creates and populates the child
collection:
public OrderLineItems FetchList(int orderId)
{
var result = new OrderLineItems();
MarkAsChild(result);
Using CSLA 4: Data Access Page 191
Rev 1.0
result.RaiseListChangedEvents = false;
using (var ctx = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities"))
{
var data = from r in ctx.ObjectContext.OrderLineItems
where r.OrderId == orderId
select r;
var olpd = new OrderLineItemPersonDal();
foreach (var item in data)
{
var child = new Library.OrderLineItem();
MarkAsChild(child);
MarkOld(child);
var childId = item.Id;
LoadProperty(child, Library.OrderLineItem.IdProperty, childId);
if (item.ShipDate.HasValue)
LoadProperty(child, Library.OrderLineItem.ShipDateProperty, item.ShipDate.Value);
LoadProperty(child, Library.OrderLineItem.PersonsProperty, olpd.FetchList(childId));
result.Add(child);
}
}
result.RaiseListChangedEvents = true;
return result;
}
This method uses an EF query to get the list of line item entities, and those entity objects are
used to load individual OrderLineItem child objects with data.
ADO.NET Implementation
The SqlCe implementation may be easier to understand, because it uses a more straightforward
SQL query against the OrderLinePersons link table:
public OrderLinePersons FetchList(int lineItemId)
{
var result = new OrderLinePersons();
MarkAsChild(result);
result.RaiseListChangedEvents = false;
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var cm = ctx.Connection.CreateCommand();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText =
"SELECT LineItemId,PersonId FROM OrderLinePersons WHERE LineItemId=@lineItemId";
cm.Parameters.Add("@lineItemId", lineItemId);
using (var dr = cm.ExecuteReader())
{
while (dr.Read())
{
var child = new OrderLinePerson();
MarkAsChild(child);
MarkOld(child);
LoadProperty(child, OrderLinePerson.LineItemIdProperty, dr.GetInt32(0));
LoadProperty(child, OrderLinePerson.PersonIdProperty, dr.GetInt32(1));
result.Add(child);
}
}
}
result.RaiseListChangedEvents = true;
return result;
}
In this case, the LineItemId and PersonId column values are directly retrieved in a single query,
and are used to populate each OrderLinePerson child object.
Both implementations achieve the same result: an OrderLinePersons collection populated with
OrderLinePerson child objects.
Throughout this entire Fetch operation, notice how every business object’s metadata is properly
set, using the protected methods from the ObjectFactory base class. All individual objects are
marked as being old with the MarkOld method, and all child objects are marked as children with the
MarkAsChild method.
Update Operation
The update operation occurs when the Save or BeginSave method is called on the OrderEdit root
object. This triggers the insert, update, or delete of the root object, along with all its child and
grandchild objects.
This method follows the same structure and steps as I discussed earlier for the PersonEdit
editable root object. The code uses private methods to perform the delete, insert, and update
actions, allowing this method to remain focused on selecting the correct action based on the
metastate of the OrderEdit business object.
The interesting part of this code is where the DeleteForOrder method on the OrderLineItemDal
object is invoked:
var old = new OrderLineItemDal();
old.DeleteForOrder(id);
This DeleteForOrder method deletes the line item data for the order. As you can imagine,
before each line item is deleted, any related child data in the OrderLinePersons table must be
deleted to avoid a relational integrity conflict.
The SqlCe implementation in the OrderLineItemDal class looks like this:
public void DeleteForOrder(int orderId)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
// delete the line item person data
using (var cm = ctx.Connection.CreateCommand())
{
var lineItems = new List<int>();
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id FROM OrderLineItem WHERE OrderId=@orderId";
cm.Parameters.Add("@orderId", orderId);
using (var dr = cm.ExecuteReader())
while (dr.Read())
lineItems.Add(dr.GetInt32(0));
var olpd = new OrderLineItemPersonDal();
foreach (var item in lineItems)
olpd.DeleteForLineItem(item);
}
When implementing this behavior with ADO.NET, the trick is to avoid reusing the database
connection when it has an active data reader in use. To avoid any attempts to delete child data
while retrieving the list of line items, the code copies the line item Id values into a List<int> so it
can dispose the data reader before calling the DeleteForLineItem method on the
OrderLineItemPersonDal object to delete the child data for each line item.
The DeleteForLineItem method in the OrderLineItemPersonDal class deletes the data for the
specified line item. For example, here’s the SqlCe implementation:
public void DeleteForLineItem(int lineItemId)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
To recap, the Update method in the OrderDal class calls the OrderLineItemDal object to delete
the order’s line items before deleting the order data. The OrderLineItemDal object’s
DeleteForOrder method calls the OrderLineItemPersonDal object to delete the line item’s person
data before deleting the line item records.
You could choose to implement this process in many different ways. In a real application you will
probably use cascading deletes in the database, or you will use more sophisticated database DELETE
queries to optimize this process.
I chose this particular implementation to provide complete detail about the process, and to
demonstrate how each object factory class can implement behaviors relative to a data entity.
The UpdateList method in the OrderLineItemDal class is basically the same in all three DAL
implementations. The only difference between the implementations is that the SqlEf and SqlCe
versions wrap the code in a using block for an ObjectContextManager or ConnectionManager
respectively. This ensures that the same database connection is reused throughout the process.
Here’s the code for the SqlCe implementation of the UpdateList method in the OrderLineItemDal
class:
public void UpdateList(OrderEdit order, OrderLineItems orderLineItems)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var olpd = new OrderLineItemPersonDal();
var deletedList = GetDeletedList<OrderLineItem>(orderLineItems);
foreach (var item in deletedList)
{
olpd.DeleteForLineItem(item.Id);
Delete(item);
}
deletedList.Clear();
Like the other collection update methods you’ve seen, this one updates the items in the
DeletedList, then it clears the DeletedList, and finally it updates the items in the collection itself.
The Delete, Insert, and Update methods delete, insert, and update the OrderLineItem child
objects. I won’t show the code for all of these methods, because they are comparable to methods
you’ve already seen.
The important thing to notice are the DeleteForLineItem and UpdateList methods that are
called on the OrderLineItemPersonDal object to update the OrderLinePersons child collection
contained in each OrderLineItem object.
I discussed the DeleteForLineItem method in the OrderLinePersons class earlier in this section.
This code is reusing that same method.
Once all the items in the OrderLineItems collection’s DeletedList have been deleted, each item
in the collection is inserted or updated based on the child object’s metastate.
This implementation retrieves the Order entity using an EF query, deletes the entity from the
ObjectContext, and saves the changes with the SaveChanges method. Because the EF entity model
understands the data relationships in the database, it automatically deletes all relevant data.
The SqlCe implementation is more complex, because it must take care of deleting the line item
child data before deleting the order data:
public void Delete(int id)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var old = new OrderLineItemDal();
old.DeleteForOrder(id);
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "DELETE [Order] WHERE Id=@id";
cm.Parameters.Add("@id", id);
var rowsAffected = cm.ExecuteNonQuery();
if (rowsAffected == 0)
throw new InvalidOperationException("Order");
}
}
}
Notice how this code reuses same the DeleteForOrder method on the OrderLineItemDal object
that I discussed earlier in this section. Based on that earlier discussion, you should remember that
this DeleteForOrder method uses the DeleteForLineItem method of the OrderLIneItemPersonDal
object to first delete the person data for each line item.
As I discussed in Chapter 5, a command object might or might not interact with the database on
the server. A command object represents any behavior that needs to be executed on the server,
possibly including database interaction, launching a workflow, running an algorithm, or interacting
with other server resources such as the server’s file system.
This includes the possibility of interacting with other business objects on the application server,
and that is the technique I used to implement the Execute method for the OrderShipper command
object. This Execute method is in the OrderDal class of each DAL project because the primary focus
is on the order data entity.
Execute Operation
Each of the three Execute method implementations is basically the same, with the exception that
the SqlCe and SqlEf implementations have the Transactional attribute, and they wrap the code in
a using block for a ConnectionManager and ObjectContextManager to ensure one database
connection is resused for all database interactions.
Here’s the SqlEf implementation in the OrderDal class:
[Csla.Transactional(Csla.TransactionalTypes.TransactionScope)]
public OrderShipper Execute(OrderShipper obj)
{
using (var ctx = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities"))
{
// ship order and generate shipping number
var order = OrderEdit.GetOrderEdit(obj.OrderId);
LoadProperty(obj, OrderEdit.OrderEditProperty, DateTime.Today);
order = order.Save();
1. Retrieving objects
2. Updating objects
A unit of work object that performs object retrieval is typically implemented as a subclass of the
ReadOnlyBase class. This type of unit of work is a special case of a read-only object, where the
properties of the unit of work object are instances of other business objects. I’ll walk through an
example of this type of unit of work later in this section.
A unit of work object that performs an update of objects is implemented as a command object.
In this case the command object’s properties are instances of the editable root objects that are to
be saved.
Retrieving Objects
The PersonEditUoW class in the Library.Net project is an implementation of a read-only unit of
work stereotype. This class uses the ObjectFactory attribute to provide the data portal with the
name of the object factory type and Fetch method name that should be used to persist this
business object:
[Csla.Server.ObjectFactory("PersonDal", "FetchUoW")]
[Serializable]
public class PersonEditUoW : ReadOnlyBase<PersonEditUoW>
This means that the PersonDal class in each of the three DAL projects includes a FetchUoW
method that is responsible for implementing the Fetch operation for the PersonEditUoW business
object.
Like in Chapter 5, the existing static factory methods on the PersonEdit and CategoryList
classes are used to fetch the two business objects that are retrieved by the PersonEditUoW object.
This means that the FetchUoW methods are essentially the same in each DAL project. Here’s the
SqlEf implementation:
public PersonEditUoW FetchUoW(int personId)
{
var result = new PersonEditUoW();
using (var ctx = ObjectContextManager<SqlDbEntities>.GetManager("SqlDbEntities"))
{
LoadProperty(result, PersonEditUoW.PersonEditProperty, PersonEdit.GetPersonEdit(personId));
LoadProperty(result, PersonEditUoW.CategoryListProperty, CategoryList.GetCategoryList());
}
return result;
}
Updating Objects
The PersonsUpdater class in the Library.Net project is an implementation of a unit of work object
that updates multiple editable root objects as part of a single unit of work and a single database
transaction.
This class includes an ObjectFactory attribute:
[Csla.Server.ObjectFactory("PersonDal")]
[Serializable]
public class PersonsUpdater : CommandBase<PersonsUpdater>
This means that the PersonDal class in each DAL project includes an Execute method to
implement the server-side behavior for this unit of work object. The Execute method uses the
existing behaviors of the PersonEdit editable root objects it is saving. For example, here’s the
SqlCe implementation:
[Csla.Transactional(Csla.TransactionalTypes.TransactionScope)]
public PersonsUpdater Execute(PersonsUpdater obj)
{
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
var person1 = obj.Person1.Save();
LoadProperty(obj, PersonsUpdater.Person1Property, person1);
var person2 = obj.Person2.Save();
LoadProperty(obj, PersonsUpdater.Person2Property, person2);
}
return obj;
}
The SqlCe and SqlEf implementations use the Transactional attribute to ensure that the entire
operation is transactionally protected.
They also wrap the code in a using block for the object context or database connection manager
to ensure that the same database connection is reused throughout the process.
The existing synchronous Save methods from the PersonEdit root objects are used to save the
two objects, and the updated PersonEdit objects are placed into the Person1 and Person2
properties of the command object so they are returned to the calling code.
At this point you should understand how persistence is implemented for unit of work objects,
including read-only and update-based objects.
A custom Fetch method name is supplied because the PersonDal already has a Fetch method
that retrieves the PersonEdit business object.
Fetch Operation
The Fetch operation is implemented in each DAL project’s PersonDal class. The method in each
class is named FetchList, based on the value in the ObjectFactory attribute applied to the
PersonList read-only list class.
A Fetch method for the PersonList read-only list must implement the following steps:
5. Create an instance of the PersonInfo child object for each row of data
You can see how each of the steps is implemented by this method by using the protected
methods provided by the ObjectFactory base class.
The result is that a fully populated PersonList object is returned through the data portal to the
calling code.
The CategoryDal object factory type is used because it represents the logical category data
entity.
Fetch Operation
Each of the three DAL projects implements a FetchList method in the CategoryDal class. They
follow the same steps as for any read-only list. The only difference is that a name-value list supplies
its own NameValuePair child object type, as I discussed in Chapter 5.
The SqlCe implementation looks like this:
public CategoryList FetchList()
{
var result = new CategoryList();
SetIsReadOnly(result, false);
var rlce = result.RaiseListChangedEvents;
result.RaiseListChangedEvents = false;
using (var ctx = ConnectionManager<SqlCeConnection>.GetManager("LocalDb"))
{
using (var cm = ctx.Connection.CreateCommand())
{
cm.CommandType = System.Data.CommandType.Text;
cm.CommandText = "SELECT Id,Category FROM Category";
using (var dr = cm.ExecuteReader())
{
var idIndex = dr.GetOrdinal("Id");
var categoryIndex = dr.GetOrdinal("Category");
while (dr.Read())
result.Add(new Csla.NameValueListBase<int, string>.NameValuePair(
dr.GetInt32(idIndex), dr.GetString(categoryIndex)));
}
}
}
result.RaiseListChangedEvents = true;
SetIsReadOnly(result, true);
Using CSLA 4: Data Access Page 203
Rev 1.0
return result;
}
Each row of data retrieved from the database is used to create a new read-only child object:
result.Add(new Csla.NameValueListBase<int, string>.NameValuePair(
dr.GetInt32(idIndex), dr.GetString(categoryIndex)));
1. Encapsulated invoke
2. Factory implementation
3. Factory invoke
4. Encapsulated implementation
And you have walked through the encapsulated invoke and factory implementation models in
detail.
This is the third book in the Using CSLA 4 ebook series. Subsequent ebooks will explore data
portal configuration, authentication, and how to use a business layer composed of domain objects
to create various types of application interface.