| |
DevForce® Classic Tech Tips |
|
|
|
| Dynamic Entity Types |  |
| Dynamic
Entity
Types |
Level 300
DevForce Enterprise |
Sep 28, 06 |
|
DevForce developers define “static” business
object types at design time by
mapping class definitions to objects
in data source schemas such as tables,
views, and stored procedures in relational
databases.
Sometimes we don’t know the structure of the class we’ll
need until runtime. For example:
- A particular search can fetch
data from many rows of a very large
table depending upon how the user
structures the query. Poor performance
is a huge risk. We want to retrieve
the minimum number of columns necessary
to present the result in a grid.
We don’t know which columns
until the user specifies the query.
- We want to generate some aggregate
statistics from a table (counts,
averages, etc.). We compose a query
to retrieve them although we don’t
know what we’re after (the
columns returned by the query) until
runtime, perhaps because the user
picks the statistics from a menu.
- We may need to build a class around
a table we discover in the runtime
database – a table that didn’t
exist in the design-time database.
This can be a “user-defined
table” that our customer has
added to the database in order to
extend and customize user information
managed by our application.
In all cases we’d like to represent
the data as entities in our business
object model. But we can’t use
any of the static entity types output
by the Object Mapper because we don’t
know the “schema” of those
entities until runtime.
Enter the “Dynamic
Entity Type.” As of
release 3.2.1.1, DevForce developers
can create a new “dynamic” type – a
new class – at runtime.
Dynamic entity type instances can
be queried, created, modified, and
deleted. They reside in the entity
cache of a PersistenceManager’s and
inherit from the DevForce Entity class,
just like instances of the static entity
types. A dynamic entity type may even
be shared with other clients if the
clients are n-tier deployed and use
the same name for the type.
Keyed and Unkeyed Dynamic
Entity Types
Dynamic entity types come in two basic flavors: those defined with, and
those defined without a primary key.
Dynamic entity types with a primary key operate almost exactly
like a statically defined DevForce entity type. Query results are merged
into a PersistenceManager according
to the query’s MergeStrategy.
The primary key helps the merge discover if the arriving entity is new
to the cache or is already present; if present, the strategy determines
whether the arriving entity updates the cached entity, replaces it, or
is ignored.
Merge logic depends upon schema consistency across queries. It follows
that the structure of the result of all queries for a keyed dynamic entity
type must match the schema for that type. The type’s schema is
only “open” for the first query.
On the other hand, when we query for dynamic entity types without a
primary key, the PersistenceManager does not merge the results. Absent
a primary key, it cannot determine if the arriving entity is already
in the cache. Therefore, for keyless dynamic entities, the PersistenceManager
first discards all prior instances of the type and then fills the cache
with the query results. And in this circumstance, schema consistency
is not an issue, so the PersistenceManager, upon detecting a difference,
simply drops the old schema and adopts the new schema implied in the
query result.
Creating Dynamic Entity Types
Dynamic entity types can be created, with or without a primary key, using
the CreateType() method of the new DynamicEntityTypeBuilder class.
Here, for example, is the code to create a dynamic entity type with
a primary key, defined by name.
|
C#:
Type type1 =
DynamicEntityTypeBuilder.CreateType("foo1", "IdeaBladeTest1", “LastName”);
VB.NET:
Dim type1 As Type = DynamicEntityTypeBuilder.CreateType( _
"foo1", "IdeaBladeTest1", “LastName”)
|
In the above example, the first argument
is the name for the type; the second argument
is a DevForce DataSourceKeyName;
the final argument is the name of the primary
key column.
You can create a multi-part key simply by specifying the additional column
names in subsequent parameters (no limit): |
C#:
Type type1 =
DynamicEntityTypeBuilder.CreateType("foo1", "IdeaBladeTest1", “CompanyName”, “EmployeeNumber”);
VB.NET:
Dim type1 As Type = DynamicEntityTypeBuilder.CreateType( _
"foo1", "IdeaBladeTest1", “CompanyName”, “EmployeeNumber”)
|
| Key columns can also be referenced by
their column index. The equivalent of the
multi-part key specification just illustrated
would be the following, assuming that the
column indexes for CompanyName and EmployeeNumber
are 0 and 1, respectively. That data should
come from the default datasource. |
C#:
Type aDynamicType =
DynamicEntityTypeBuilder.CreateType("foo1", "Default", 0,1);
VB.NET:
Dim aDynamicType As Type = DynamicEntityTypeBuilder.CreateType( _
"foo1", "Default", 0,1)
|
| To create a dynamic entity type without a
primary key, simply omit the primary key
column: |
C#:
Type type1 = DynamicEntityTypeBuilder.CreateType("foo1", "IdeaBladeTest1");
VB.NET:
Dim type1 As Type = DynamicEntityTypeBuilder.CreateType( _
"foo1", "IdeaBladeTest1")
|
An additional option for creating
dynamic entity types will be available
in the next release of DevForce, scheduled
for early November: declaring the schema
programmatically at runtime. That will
permit the creation of an entity that
has no database table behind it at all.
Instances of such an entity can then
be created and populated programmatically.
And note that any instance of
a dynamic entity, whether backed by a
database table or not, can be persisted
to a local file using the PersistenceManager’s
familiar SaveEntitySet() method.
Querying for Instances of
Dynamic Entity Types
Dynamic entity types can be queried either from the PersistenceServer via
a PassthruRdbQuery or
from the local PersistenceManager via a normal EntityQuery.
(A forthcoming version of this feature will support querying for dynamic
type entities from the PersistenceServer via
either the StoredProcRdbQuery or
the WsQuery.)
Querying from the PersistenceServer (Backend
Database)
|
C#:
PersistenceManager pm = PersistenceManager.DefaultManager;
Type type1 =
DynamicEntityTypeBuilder.CreateType("foo1", " Default",”LastName”);
IEntityQuery query1 = new PassthruRdbQuery(
type1, "select FirstName, LastName from Employee");
IList entities1 = pm.GetEntities(query);
Type type2 = DynamicEntityTypeBuilder.CreateType("foo2", "Default");
IEntityQuery query1 =
new PassthruRdbQuery(type2, "select count(*) from orders");
IList entities2 = pm.GetEntities(query);
VB.NET:
Dim pm As PersistenceManager = PersistenceManager.DefaultManager
Dim type1 As Type = DynamicEntityTypeBuilder.CreateType( _
"foo1", " Default",”LastName”)
Dim query1 As IEntityQuery = New PassthruRdbQuery( _
type1, "select FirstName, LastName from Employee")
Dim entities1 As IList(Of DynamicEntity) = _
pm.GetEntities(Of DynamicEntity)(query)
Dim type2 As Type = DynamicEntityTypeBuilder.CreateType("foo2", "Default")
Dim query1 As IEntityQuery = _
New PassthruRdbQuery(type2, "select count(*) from orders")
Dim entities2 As IList(Of DynamicEntity) = _
pm.GetEntities(Of DynamicEntity)(query)
|
| Querying from the PersistenceManager
Cache |
C#:
PersistenceManager pm = PersistenceManager.DefaultManager;
Type type1 =
DynamicEntityTypeBuilder.CreateType("foo1", "Default", ”LastName”);
// EntityQueries against dynamic entities automatically have
// EnableUDFQueries=true
EntityQuery query = new EntityQuery(type1, "LastName", EntityQueryOp.LT, "G");
IList entities =
pm.GetEntities(query, QueryStrategy.CacheOnly);
VB.NET:
Dim pm As PersistenceManager = PersistenceManager.DefaultManager
Dim type1 As Type = DynamicEntityTypeBuilder.CreateType( _
"foo1", " Default",”LastName”)
' EntityQueries against dynamic entities automatically have
' EnableUDFQueries=true
Dim query As EntityQuery = _
New EntityQuery(type1, "LastName", EntityQueryOp.LT, "G")
Dim entities As IList(Of DynamicEntity) = _
pm.GetEntities(Of Entity)(query, QueryStrategy.CacheOnly)
|
Accessing Data in a Dynamic
Entity Type Object
You can access the data in a dynamic entity type object by name, or by
index, with the Entity indexing method.
|
C#:
String lastName;
lastName = (String) aDynamicEntity[“LastName”]; // or
lastName = (String) aDynamicEntity[1];
VB.NET:
Dim lastName As String
lastName = CType(aDynamicEntity(“LastName”), String) ' or
lastName = CType(aDynamicEntity(1), String)
|
This is the same approach we use to
access data in a User-Defined Field (UDF).
Saving Changes
Currently new, modified, or deleted dynamic entities in the PersistenceManager
cannot be saved back to the backend datastore. This will be supported
in the next release of DevForce. Meanwhile, enjoy the local-persistence-only
variety!
|
|
|
|
|