IdeaBlade DevForce Q&A

prettybadelyngeSoftware and s/w Development

Nov 18, 2013 (3 years and 10 months ago)

101 views


prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
© Copyright 2006, IdeaBlade, Inc, all rights reserved

Printed
11/18/2013


DevForce

Questions & Answers


Version
3.5.1

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.



Copyright ©
2006, IdeaBlade, Inc, all rights reserved

116

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

i

Table of Contents

Preface

................................
................................
................................
................................
...........

1

Purpose of This Document

................................
................................
................................
................................
........

1

Related DevForce Documentation

................................
................................
................................
...........................

1

Intended Audience

................................
................................
................................
................................
......................

1

Section Organization

................................
................................
................................
................................
..................

2

Company Facts

................................
................................
................................
................................
............................

2

Section 1: Getting Started

................................
................................
................................
............

3

DevForce and Visual Studio
................................
................................
................................
................................
.......

3

DevForce and SQL Server 2005

................................
................................
................................
...............................

3

“Wizard was Interrupted” Message During DevForce Installation

................................
................................
......

3

Problem with the “IdeaBlade Object Mapper” Entry in the German E
dition of Visual Studio 2005

..............

4

Section 2: Business Object Mapping

................................
................................
...........................

6

Tech Tip: Unnatural Keys: When Customer's Care About Primary

Key Values

................................
.................

6

Databases That Are Compatible with DevForce

................................
................................
................................
.

10

Generating Custom Primary Key Values in DevForce

................................
................................
........................

10

Working with Tightly Coupled (1
-
to
-
1) Entities

................................
................................
................................
....

11

Working with Composite Keys

................................
................................
................................
...............................

11

Building Classes From System Tables Using the Object Mapper

................................
................................
.....

12

Section 3: Object Persistence

................................
................................
................................
....

14

Tech Tip: Web Service Publishi
ng

................................
................................
................................
..........................

14

Tech Tip: Asynchronous Queries

................................
................................
................................
............................

15

Tech Tip: Data Source Extensions

................................
................................
................................
.........................

16

Tech Tip: Checkpointing

................................
................................
................................
................................
..........

17

Tech Tip: Concurrency Checking with the SQL Server Timestamp

................................
................................
...

18

Concurrency in Master/Det
ail Relationships

................................
................................
................................
......

21

GUID Keys and DataBase Performance

................................
................................
................................
...............

25

GetEntityGraph

................................
................................
................................
................................
.........................

33

Paged RdbQueries

................................
................................
................................
................................
...................

33

Tech Tip: Span Queries

................................
................................
................................
................................
............

34

Multi
-
Threading In a DevForce Application

................................
................................
................................
..........

35

Section 4: User Interfaces

................................
................................
................................
...........

37

Tech Tip: Dynamic Entity Types

................................
................................
................................
.............................

37

Computing Aggregate Valu
es Efficiently with Dynamic Entities

................................
................................
......

41

Using Dynamic Properties to Access Values in a Dynamic Entity

................................
................................
....

43

Tech Tip: Use ReplaceRa
nge() to Populate Your EntityList

................................
................................
...............

45

Changing the ErrorProvider Behavior for Loose Controls

................................
................................
..................

49

PersistenceManager.Clear() and En
tityLists

................................
................................
................................
........

49

How to Recover Lost Bindings

................................
................................
................................
...............................

52

Forcing the PropertyChanged Event to Fire

................................
................................
................................
.........

54

DevForce Support for Specific Versions of the Developer Express Control Suite

................................
..........

55

Tech Tip: The Document Outline Window

................................
................................
................................
............

56

Tech Tip: Keep Your Lists Current With the EntityListManager

................................
................................
........

59

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.



Copyright ©
2006, IdeaBlade, Inc, all rights reserved

116

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

ii

Tech Tip: Refactoring Your User Interface with DataConverters and ViewDescriptors

................................
.

61

Tech Tip: Split Button Configuration

................................
................................
................................
.....................

63

Tech Tip: Use Validate() to Complete DataBinding

................................
................................
.............................

65

Tech Tip: Working with User
-
Defined Fields

................................
................................
................................
........

66

Tech Tip: Binding User
-
Defined Fields to Controls in Your User Interface

................................
.......................

70

T
ech Tip: ListBox Unbound
-

Programming List Controls the DevForce Way

................................
.................

74

Adding Items to a Child Grid

................................
................................
................................
................................
..

77

ReadOnlyEntityList v. E
ntityList

................................
................................
................................
.......................

78

UI Mechanisms for Add & Delete
................................
................................
................................
....................

79

Tech Tip: Working with a ReadOnlyEntityList

................................
................................
................................
......

81

Tech Tip: Binding a Business Object Property To a Set of .NET RadioButtons

................................
...............

83

Section 5: General Development

................................
................................
...............................

89

Tech Tip: The BindableList(of T)

................................
................................
................................
.............................

89

Tech Tip: Create a Generic When T is unknown

................................
................................
................................
..

91

Tech Tip: How to prevent the d
ebugger from intercepting an exception meant for someone else

...........

96

Section 6: Business Object Server

................................
................................
.............................

99

Generating a Report Server
-
Side Using a Remote Procedure Call

................................
................................
..

99

Section 7: Disconnected Applications

................................
................................
....................

101

Tech Tip: Supporting Disconnected Applications

................................
................................
..............................

101

Working with a Distributed Database

................................
................................
................................
................

102

Section 8: Security

................................
................................
................................
....................

104

Implementing Role
-
Based Security in a DevForce App

................................
................................
...................

104

Section 9: Deployment

................................
................................
................................
.............

106

Binary Stream ‘50’ Does Not Contain a Valid Bin
aryHeader

................................
................................
..........

106

Using a Loose Copy of IdeaBlade.ibconfig for IIS Deployment

................................
................................
.......

106

Trace File Logging and File I/O Permissions

................................
................................
................................
.....

107

Section 10: Troubleshooting
................................
................................
................................
....

109

Tech Tip: What is my DevForce Application doing? Use the TraceViewer to Find Out!

..............................

109

Tech Tip: I Break for Exceptions

................................
................................
................................
..........................

1
12

Finding Information on a DevForce Error Message

................................
................................
..........................

114

Section 11: Funhouse/Cabana Sample Apps

................................
................................
........

115

Cabana in VB?

................................
................................
................................
................................
........................

115

Implementing Funhouse
-
Style BaseEntity Inheritance i
n Your Application

................................
.................

115

Problem Logging Into Funhouse

................................
................................
................................
.........................

116

Topic

................................
................................
................................
................................
................................
.........

116

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Preface

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

1

Preface

Purpose of This Docu
ment

At IdeaBlade we naturally receive a continuing stream of questions on all aspects of DevForce and DevForce
development. Many of these we answer through
an
email or with a short document, either of which may sometimes
include a code snippet or even a
complete (though typically small and targetted) Visual Studio solution.

These replies
often

lack
the polish of material in our Concepts Manual, Developers Guide, and other reference
documents; even so, the

recipients have
told us
they consider
the
ir conten
t

in
valuable
.
A
ccordingly, we’ve decided
to
make them available to you with a minimum of turn
-
around delay
.

In this document
you will find rough
-
and
-
ready replies
,

in a searchable
medium,
to all manner of questions
.
When a reply includes an attachment,
a link will
be provided to
a
zip file
.

We expect that this document will grow rapidly. Occasionally, as time permits, we will ourselves harvest some of
the material herein for transport to the Developers Guide or even Concepts Manual.

We’
v
e
also
folded i
n
our Tech Tips, which are
distributed first as
email
s to our mailing list,
and which have
also
been collected on our web site. They seem much in the spirit of Q&A, and we thought you’d appreciate having
them
, too,

in a searchable medium. The Tech Tips
a
re

pretty polish
ed.

As when distributed elsewhere, the
y

are
identified as to their Technical Level (100 Fundamentals, 200 Intermed
iate, 300 Advanced, 400 Expert);

the
minimum edition of DevForce to which they apply (Express, Professional, Enterprise
, Busin
ess Object Server); and
their date of first distribution.

We hope
you will find in this document
a wealth of helpful material that would otherwise be much more difficult for
you to learn about and obtain.

Related DevForce Documentation

There are other mate
rials that can help you.

DevForce Installation Guide



Covers all aspects of installing DevForce, both initial install and updates.

DevForce Release Notes



Explains what is new, what has changed, and the implications for existing DevForce
applications. It

is a “
must read
” every time you update your application to a new version of DevForce.

DevForce Concepts Manual



The Concepts Manual explains the broader goals and concepts addressed by
DevForce and is a prerequisite for making use of this Developers Guid
e.

This is the place to learn why DevForce works as it does and is the most important companion to this guide.
You will also find a
glossary of terms

used everywhere in our documentation.

DevForce Developers’ Guide



A guide to using DevForce in your appli
cations, the “How To” companion to
this Concepts Manual.


DevForce Reference Help



This is the detail code documentation. Each namespace, class, and method is
documented individually. Important areas contain code examples.

DevForce
Instructional Units



T
hese are topic
-
focussed folders that may contain tutorials, PowerPoint slide
decs, non
-
tutorial code solutions, and reference materials. A pared
-
down version of the Instructional Units are
The tutorials show, in a step
-
by
-
step manner, how to build simple a
pplications using DevForce.

Intended Audience

This Developers Guide targets developers building applications with DevForce. We
assume you
are familiar with
.NET, Visual Studio, and

.NET Windows Forms development; and we strongly suggest that, as a startin
g point for
IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Preface

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

2

DevForce development, you read the Concepts Manual and the Developers Guide, and also familiarize yourself with
the tutorials and various code solutions
included in the Instructional Units for the product.
1

Section

Organization

As a starting po
int, this document is divided into
Section
s that roughly parallel th
e chapters
in the Developers Guide.
If, as we accumulate materials, some other organization looks more promising, we’ll change it.

Section

1
,
Getting Started
, addresses the basics of installing DevForce and building your application, including
design guidelines and conventions.

Section

2
,
Business Object M
apping
, addresses the details of defining your business object model with the
DevForce Object Mapping Tool (AKA, the Object Mapper).

Section

3
,
Object

Persistence
,
addresses querying, creating,

updating, and deleting the business object entities that
you defined with the
DevForce

Object Mapping Tool.

Section

4
,
User Interfaces
, addresses user interfaces that work with business object entities.

Section

5
,
User Interfaces
, addresses coding issues that span model and UI.

Section

6
,
Business Object Server
, addresses the special features and requirements for using the Business Ob
ject
Server in an n
-
tier application.

Section

7
,
Disconnected Applications
,
addresses features and issues related to running applications while
disconnected

from a back
-
end data server.

Section

8
,
Security
,

addresses security
-
related features and strategies for a DevForce application.

Section

9
,
Deployment
,

address
es the deployment of your application.

Section

10
,

Troubleshooting
, addresses testing, debugging, and the use of IdeaBlade technical support
.

Company Facts

Please con
tact us or visit us at our headquarters in the San Francisco Bay Area:


6425 Christie Avenue, Suite 260

Emeryville, CA 94608

510.596.5100

www.ideablade.com


support@ideablade.com






1

A subset of the latter are included in the product’s installation package; complete sets are available on the Learning Materi
als
page of the IdeaBlade web site at
http://www.ideablade.com/learningmaterials.html
.

IdeaBlade DevForce Developers Guide
,
v.
E
rror! Reference source not found.


Getting Started

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

3

Section

1:

Getting Started

Questions and tips in this section

address the basics of installing DevForce and building your application,
including design guidelines and conventions.

DevForce and Visua
l Studio

Question:

What edition of Visual Studio do I need when working with DevForce?

Attachment:

None.

Answer
:

DevForce run
with
VS 2005 Standard

Edition or higher
.


Y
ou cannot install DevForce with Visual Studio
Express
, as that edition does not perm
it third
-
party components (such as the DevForce Object Mapper) to
be integrated.

DevForce and SQL Server 2005

Question:

What edition of SQL Server 2005 is required for working with DevForce?

Attachment:

None.

Answer
:

We hav
e verified

the
use
of DevForce
with both SQL Server 2005 and SQL Server 2005 Express Edition.


“Wizard was Interrupted” Message During DevForce
Installation

Question:

I have been unable to install


the installation states it has been interrupted before it could be fully installed.

Att
achment:

None.

Answer
:

From the Troubleshooting section of the Installation Guide:

If you get a message saying that the “wizard was interrupted”, you probably have run into a Windows SP2
operating system security issue. To fix this problem, read the Macr
ovision Knowledge Base article at:

http://support.installshield.com/kb/view.asp?articleid=Q111303


You might
also be interested in reading:

http://episteme.arstechnica.com/groupee/forums/
a/tpc/f/99609816/m/959005056731

IdeaBlade DevForce Developers Guide
,
v.
E
rror! Reference source not found.


Getting Started

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

4

Problem with the “IdeaBlade Object Mapper” Entry in
the German Edition of Visual Studio 2005

Question:

I can't get the “IdeaBlade Object Mapper” menu entry to show up in VS2005 (German Edition).

I have already tried the me
asures in the installation guide, but I can't get it to work. I located the add
-
in in
the folder

C:
\
Dokumente und Einstellungen
\
All Users
\
Application Data
\
Microsoft
\
MSEnvShared
\
Addins.

The Object Mapper Installer shows an error message that shows:

Destin
ation folder missing: C:
\
Dokumente und Einstellungen
\
All
Users
\
Anwendungsdaten
\
Microsoft
\
MSEnvShared
\
Addins.

Note that the Object Mapper Installer tries to use the German folder name ("Anwendungsdaten" instead of
"Application Data"), while the original Set
up obviously installed in "Application Data" (both use the
German "Dokumente und Einstellungen", though).

I also tried to rename the add
-
in in the folder where I found it, restarted VS, renamed again and restartet VS
again, to no avail. It seems to me that

the Add
-
In might be looking for a "Tools" menu, but in the German
version this menu is named "Extras".

Attachment:

None.

Answer
:

It appears that the InstallShield installer and the Object Mapper Installer have different opinions as to
where the Add
-
Ins a
re located. The Object Mapper Installer uses the registry, so we believe it has the
correct opinion. The InstallShield
-
based Installer knows about certain "Special Folders" and knows the
"Internationalized names" for these folders. Unfortunately, it doesn'
t have any "Special Folder" for the
"Application Data" folder underneath "All Users". Instead, it "hard
-
wires" the name to "Application Data"
underneath the "Special Folder" for "All Users".

My guess is that you may be able to fix your problem by copying t
he three files:
(IdeaBlade.DevTools.Orm.AddIn, IdeaBlade.DevTools.Orm.AddIn.dll, Visual.Studio.CommandBars.dll )
from the path that contains "Application Data" to the path that contains "Anwendungsdaten". If this doesn't
work, let me know. If necessary, we

can build you a new setup.exe.

The fix will require me to add a custom action to install/uninstall the files in the correct location. Since we
don't have a version of a German XP or a German Visual Studio, I am wondering if you could help me test
the inst
allation.


Customer replied:

I've tried again to get the ORM menu entry and now I succeeded, through the "Customize
-

Addins"
function, dragging the entry to the menu. The situation regarding the directories is as follows:

Although my OS and my VS2005 soft
ware are German, the proper directory for the Visual Studio plugins
is obviously

C:
\
Dokumente und Einstellungen
\
All Users
\
Application Data
\
Microsoft
\
MSEnvShared
\
Addins.

Note that this is mixed: "Dokumente und Einstellungen" is German, "Application Data" i
s not.

The "hard
-
wired" name in Installshield seems to be right.

In the folder

IdeaBlade DevForce Developers Guide
,
v.
E
rror! Reference source not found.


Getting Started

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

5

C:
\
Dokumente und Einstellungen
\
All Users
\
Anwendungsdaten
\
Microsoft

(the "fully" German version), there is no folder "MSEnvShared". I created it and the content therein, but it
didn't seem to have any impact. I deleted it again, and the ORM still works.


IdeaBlade responded:

Thank you so much for your information. It is very helpful.

We’re surprised by what you found. We had thought that the Germanized folder name would be the co
rrect
one, but your experiments show that this is not the case. It makes me suspect that this is really a Microsoft
bug.

This means that what I need to change is the Object Mapper Installer, not the Installer.

It is interesting that you succeeded through t
he "Customize
-

Addins" function, dragging the entry to the
menu. This workaround was discovered when I was working with another customer. This customer was
also from Germany!!!

We'll add the fix

to the Object Mapper Installer.
IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Business Object Mapping

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

6

Section

2
:

Business Object M
apping

Questions and tips in this section

address the details of defining your business object model with the
DevForce Object Mapping Tool (AKA, the Object Mapper).

Tech Tip:
Unnatural Keys: When Customer's Care About
Primary Key Values

Level 100

DevForce

Express

December 13, 2006

Most seasoned developers and database administrators know that primary key values should be intrinsically
meaningless. They exist for internal use only as permanent record identifiers. They really shouldn't be
shown to users.

By

such reasoning, the primary key of an Order record should be completely arbitrary. It shouldn't matter if
it is "1234567" or "96b28a7b
-
a328
-
4bf3
-
95a0
-
06a29e45f582" (which many of you recognize as the string
representation of a "Globally Unique Identifier"

or "Guid").

Our customers
-

the end users of our applications
-

are accustomed to referring to Orders by a unique
reference number. Over the years, we've trained them to like calling an order by its number, "1234567".
Thus acclimated, they start to expec
t that the next invoice created will be numbered "1234568". They start
to worry if there are gaps in the sequence
-

if the order jumps to "1234570", for example. "What happened
to '68' and '69' ?", they cry. They'll have no patience at all for "96b28a7b
-
a3
28
-
4bf3
-
95a0
-
06a29e45f582"
or its successor, "81063553
-
6686
-
41f4
-
8b50
-
130a4deb444d".

Key Misery


The customer demand for an uninterrupted progression of reference numbers is at cross purposes with our
need as developers for programming flexibility and pri
mary key stability.

We want to set a record's primary key upon insertion and never change it again. If the user creates a
temporary record and then deletes it, we don't want to care that we just burned the next id.

It's a dead certainty that the customer
s' affection for meaningful primary keys is going to plague us. Next
thing you know, they're going to ask us to fill in the sequence gaps. Then they will want to prepend the
reference number with the year of the order ("06
-
1234567") and suffix it with the
customer initials ("06
-
1234567
-
IB"). If the customer changes its name, they will want us to update the initials ("06
-
1234567
-
JC").

Did I mention that the customer wants to sort the orders by reference number? Imagine the fun we'll have
sorting a string co
nsisting of a mix of alpha decorations and an integer counter; one of my clients requires
that orders sort by integer value, regardless of prefix, yielding sequences such as "A23", "A123", "B124",
"A1123". No "leading zero" trick allowed!

"Surrogate" vs. "
Natural" Keys

The customer is always right.

Sure, the customer vaguely understands that our pain will become his pain if his requirements become too
demanding. He sort of understands that messing with the primary key could lead to bugs and data integrity
problems. But, at the end of the day, that is our problem, not his.

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Business Object Mapping

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

7

Our best hope lies in damage control. Damage control begins with a distinction between the "surrogate
key" and the "natural key".

The "surrogate key" is the permanent, arbitrary primary
key that keeps our code and data consistent and
simple. The "natural key" is the protean beast our customer loves. We can finesse the key misery problem if
we can store both values in our database tables.

Woe to the developer whose database schema is fixe
d. I offer no words of comfort, no path to salvation.

If you are fortunate and can change the database even a little, this tip is for you.

Separating Surrogate and Natural Keys


I'm going to assume that you have an existing database and that you want to
make as few changes as
necessary.

In most applications, there are only a small number of tables with natural keys; the customer doesn't care
about the ids of code tables (e.g., OrderStatus) or child tables (OrderItemDetail). The tables with natural
keys t
end to have comparatively few records; there are many more OrderItemDetail records than parent
Order records.

So our approach will waste some table space in order to achieve simplicity and flexibility.

Create a script to do the following to each table wi
th a natural key:

1.

Commit to yourself and the world that the current primary key is permanent and inviolate.

2.

Add a Natural Key column, preferrably a string.

3.

Add a Natural Key Sort column (typically an integer type).

4.

Copy the primary key values into the
two new columns (converting the primary key to string for
the Natural Key column).

5.

Constrain the new columns to be non
-
null.

6.

Constrain the new columns to be unique.

7.

Add an insert trigger to set the values of the new columns (more about this shortly).

Y
ou play your scripts and update your development database. You confirm that you get exactly what you
expected. You check the scripts into source control.

The Insert Trigger


I'll get to the definition of the insert trigger in a moment. Let's establish the

game plan first.

While a natural key may change, it isn't going to change often. Our objective is to establish a routine for
creating the natural key when we insert a new record into the table.

The new value should be unique and should avoid sequence ga
ps. The easiest way to satisfy these
constraints is to let the data tier calculate the natural key at the moment of insertion. That's the job of the
trigger.

DevForce will play along nicely as we'll soon see.

Rebuild the Business Object Model

You have t
o rebuild the business model to pick up both new natural key column properties. That's easy.

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Business Object Mapping

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

8

1.

Launch the DevForce Object Mapper.

2.

Confirm that you want it to update the model based on the schema changes.

3.

Include the two new columns.

4.

Save and close the ma
pper.

5.

Rebuild the Model project.

Update the UI to use the Natural Key Property


You are probably displaying the primary key right now. You want to switch to the natural key.

Fortunately, your application binds your UI controls to business object propert
ies and these properties are
easy to find. You should be able to search and replace references to the primary key property with the
natural key property, as in replacing "OrderId" with "OrderNumber".

Obviously you'll be careful about preserving the few pl
aces where you really want the primary key.

Saving a New Business Object

This part is automatic. You won't have to change your code at all. Here's the save sequence.

1.

The client application indicates its intention to save the new object (e.g., user press
es the "Save"
button).

2.

DevForce id generation sets the permanent primary key of the new object (the key was temporary
until this point).

3.

DevForce id fixup corrects all other entity references to the new object so that their foreign key
values now reflect

the new, permanent id.

4.

The natural key properties in the new object may be null or may have temporary values; it doesn't
matter.

5.

DevForce requests that the database insert the new object.

6.

The database insert trigger fires, calculates the natural key an
d natural key sort values, and
replaces those values in the newly inserted record.

7.

DevForce re
-
reads the inserted record.

8.

DevForce converts the updated record back into a business object.

9.

DevForce returns the business object to the client.

10.

The client U
I refreshes, revealing the natural key.

Step #7 is what makes this process so easy. DevForce always re
-
reads the entity after saving
-

both on
inserts and updates
-

in case a database trigger updates the record. That's what happens here.

Inside the Inser
t Trigger

Your trigger will be simple if you're lucky.

Suppose the customer requires that the order reference number be an integer that increments without gaps.
The ideal solution is to define the Natural Key Sort column as an autoincrement column (assum
ing MS
SQL Server).

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Business Object Mapping

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

9

Note:

Add a step to your SQL script: you will initiallize the Natural Key Sort Column the seed to the next
available integer.

The insert operation automatically sets the next Natural Key Sort Column value via the autoincrement; the
ins
ert trigger merely converts this to a string and inserts it into the Natural Key Column.

Note:

By the way, autoincrement columns do a decent job of reducing sequence gaps but they are not a guarantee.
See this link (
http://databases.aspfaq.com/database/why
-
are
-
there
-
gaps
-
in
-
my
-
identity/autoincrement
-
column.html
) for an account of ways that gaps can creep back into Natural Key values.

A slight var
iation on this scheme will satisfy the scenarios we considered earlier in which extra information
is prepended (the year) and appended (the customer initials) to an integer value that otherwise increments
by one with each insert. Your task is to write a fu
nction that reads the Natural Key Sort Column value and
returns the calculated string; the trigger stores this string into the Natural Key Column.

More exotic scenarios require more extreme calculations. You may have to abandon the autoincrementing
Natura
l Key Sort Column in favor of a next
-
integer
-
key lookup table. This is why they pay you the big
money.

The essential points are (a) that you have separated natural key generation from surrogate key generation
and (b) you've consolidated the logic into a f
unction and trigger on the data tier.

Why both a Natural Key and Natural Key Sort Column?


The Natural Key is superflous in the simple case wherein the reference number is an integer. You don't
really need both columns; you can convert the Natural Key Sor
t column into a string in the client UI. You
can add a custom property ("OrderNumber") to the business object for this purpose.

The wheels will come off when your customer demands complex decoration of the reference number.

You may think you are still in

luck if you can calculate the reference number on the fly (as you could in the
scenarios we've described). Your Natural Key property is a tad more complicated but not by much.

This approach can get you in trouble. The reference number will change if the
user modifies the order date
or the customer name; "06
-
1234567
-
IB" becomes "07
-
1234567
-
JC" . That may be ok but I'll bet your
customer is not going to be happy when reconciling printed invoices and payments to the altered order
reference number.

Note:

At
least your program is safe because the data for orders, invoices, and payments are linked internally via
the permanent surrogate keys of these records!

I suggest that you inscribe the calculated Natural Key value into the record rather than calculate it in

the UI.
You can run a database scrub process to update the Natural Key column when (and if) your customer
decides to "corrrect" the Natural Key to reflect year and customer name changes.

Keep the Natural Key Sort Column


IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Business Object Mapping

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

10

You may be tempted to keep the Na
tural Key column and do away with the Natural Key Sort column. After
all, once you've generated the Natural Key, it can be sorted easily right?

My bet is your luck will not hold and the customer is going to require complex sorting rules that are tough
to
implement. A designated sort column makes life easier for your application and for other applications
(including server side reports) that should all apply the same sorting rules consistently. It doesn't cost much;
leave it in the data.

Conclusion


It's ne
ver easy to keep your customer happy and keep your sanity. Separating surrogate keys from natural
keys can help. Use a trigger, rely on Object Mapping, and let the DevForce persistence implementation
carry the load.

Happy Coding!

Databases That Are Compa
tible with DevForce

Question:

Do you have a list of databases
--

-

other than SQL Server
--

that you know work well with DevForce?
Also, do you know if SQL Server 2000 works well with DevForce?

Attachment:

None.

Answer
:

We have customers using all of th
ese databases
:



Oracle
8, 9i,
10g



DB2



Sybase SQL Anywhere



Informix



SQL Server 2000.

There are almost certainly others that will work, as well.
I
f the database is ANSI
-
92 compliant and the
manufacturer (or someone) has created an OleDb provider that fully i
mplements the OleDb spec, the
chances are good that we can work with it.

Question:

Why doesn’t DevForce support the Microsoft Access JET engine database?

Attachment:

None.

Answer
:

For the databases it supports, DevForce generates ANSI
-
92 SQL. JET’s vers
ion of SQL is not ANSI
-
92
compliant, so to support it we would have to write a lot of special
-
case code; and since DevForce targets
enterprise, multi
-
user applications for which JET is neither designed nor well
-
suited, there is little
motivation to do so.

Generating Custom Primary Key Values in DevForce

Question:

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Business Object Mapping

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

11

To use custom IDs (i.e., non
-
GUID and non
-
Identity) in DevForce, I understand that my app must include a
class that implements your IIdGenerator interface. I’ve heard you have an implementation o
f this that
generates numeric IDs and maintains different ID pools for different entities. Where can I find it?

Attachment:

None.

Answer
:

Three implementations of IIDGenerator are shipped with the product, and are
installed in the Sample Code
directory (
e.g., C:
\
Program Files
\
IdeaBlade DevForce
\
Sample Code).

These include:


Class

Function

NumericIdGenerator

Generates sequential numeric IDs from a single pool used across all
entities.

OracleSequenceIdGenerator

Generates Oracle sequences.

PooledIdGenera
tor

Generates sequential numeric IDs from multiple, independent pools, one
for each entity.

Working with
T
ightly Coupled (1
-
to
-
1) Entities

Question:

Is there any built
-
in DevForce support for managing one
-
to
-
one relationships?

I have a main (TableA) and
a related table (TableB) which contains additional information that logically
does not belong in TableA.

The busin
ess rules are:



There should always be exactly one TableB object.



When a TableA entity is created, a related TableB record should automatically

be created. Same
when TableA entity is deleted, TableB entity is also deleted. TableB entity cannot be deleted
directly.



TableA should not expose a TableBs collection. Instead, it should expose a single TableB object
that returns the single TableB obje
ct.

Attachment:

None.

Answer
:

When examining table relations in a database, DevForce can’t tell the difference between
a 1
-
to
-
M
any
relation and a 1
-
to
-
1 relation, so it generates relations as 1
-
to
-
M
any. You can override this assigned
cardinality in the O
bject Mapper to make the relation 1
-
to
-
1; doing so will change the nature of the relation
properties that are generated into the two entity classes. Instead of a relation property representing a
collection, it will represent a single related object.

You m
ight want to look at the Instructional Unit on Generalization Hierarchies
.


T
here
you will find
a
discussion
(in the PowerPoint slides) and examples
of
different ways to approach your development in the
case where
two business objects have this tight
coup
ling
.

Working with Composite Keys

Question:

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Business Object Mapping

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

12

The Developers Guide says
:


Most of the time an object’s key consists of a single identifier and so the words “key” and “identifier” are
used interchangeably. Multipart keys are possible and sometimes necessary
but we prefer single part keys.


H
ow do you
accommodate those
in
DevForce
?

For example, h
ow would you do the equivalent of the
following for
Em
p
loyee
object with
a composite key?


[DataObjectMethod(DataObjectMethodType.Select)]



public

BindableList<Emp
loyee> GetSelectedEmployee(
string

sort, Int64 id) {



EntityQuery empQ =
new

EntityQuery(
typeof
(Employee), Employee.IdEntityColumn,
EntityQueryOp.EQ, id);



Employee emp =
this
.PersistenceManager.GetEntity<Employee>(empQ);



BindableList<Employ
ee> blist =
new

BindableList<Employee>();



blist.Add(emp);



CreateEmployeeBitMap(emp);



return

blist;



}

Also, why do

your prefer single
-
part keys
?

Attachment:

None.

Answer
:

DevForce supports the use of
composite keys
, and w
e have
many
c
ustomers who use this strategy.


Furthermore, we ne
ver (or at least
almost

never)

tell our customers that they
need to redesign their
database.

For our own work, we prefer single
-
part keys (when we have the option of choosing the key type)
--

s
imply becau
se they are more convenient to work with than composite keys. For that matter, we also prefer
“artificial” keys


those with no meaningful connection to the other information in their record. That
avoids many problems that occur when
factors external to t
he database force

that other information to
change.

To make your code work with a composite key, you would simply add additional clauses to the query to
specify the value of the remaining column(s) that participate in the key. For example, immediately
fol
lowing the statement where you instantiate the query, and before using that query in the GetEntity()
method call, you could add a statement like the following:



empQ.AddClause(
Employee.Id
Part2
EntityColumn, EntityQueryOp.EQ, id
Part2
)
;

Building Classes

From System Tables Using the Object
Mapper

Question:

I want to create a DBA utility using
DevForce
. To do so, I want to use the O
bject Mapper
to create business
objects for the system views such as sys.objects. However, I cannot see system views in the O
RM tool.

Are there plans to expose system objects in the ORM tool? Or is it to
o

DB specific?

Attachment:

None.

Answer
:

There is now (since September 2006) an option on the Object Mapper menu that exposes the system tables.
See below.

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Business Object Mapping

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

13



IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

14

Section

3
:

Object

Persistence

Questions and tips in this section

address querying, creating, updating, and deleting the business object
entities that you defined with the
DevForce

Object Mapping Tool.

Tech Tip: Web Service Publishing

Level 300

DevForce Enterprise with BOS


Nov 7, 2006

With Release 3.3, DevForce now generates the necessary code to expose your business model via web
services. You have always been able to
consume

web services in a DevForce app; and for some time, you
have also been able to base DevForce busin
ess classes on them. Now you can publish, too!

To activate this feature, you set a new
Web Visible

property of the business classes in the Object Mapper to
“As web method”. By doing so, you indicate your desire to have the specified classes exposed throug
h web
services, so the Object Mapper generates a new file, WebService.cs or WebService.vb, that contains the
web methods that will be available to clients.


For each class that you marked with “As web method” visibility, you will see two web methods in the
WebService class. One will return business objects in an array; the other (suitable for .NET clients only)
will return them in an ADO.NET DataSet.
If you set the visibility of a
Customer

class to “As web method”,
for example, the Object Mapper will generate methods
GetCustomers()

and
GetCustomersDataSet()

into
the WebService class.

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

15

Another setting of the Web Visible property, “As span object”, resul
ts in no direct web methods, but
instead permits objects of the indicated type to be returned from web methods as part of the object graph of
other objects. So, for example, if Order objects are marked “As web method” while OrderDetail objects are
marked “
As span object”, web methods will be defined for the Order objects but not for the OrderDetail
objects. However, the OrderDetail objects will be retrievable in a span query as part of the object graph of
Orders.

Classes and enums that the web service consu
mer needs to define and use queries against your web service
are included in the generated web service’s WSDL. These include Query, QueryClause, SubQuery,
QuerySpan, and others. These members become available to the consuming application through a web
refe
rence.

More information about web service publishing with DevForce is currently available from two sources. The
Release Notes for the 3.3 release of DevForce include an extended discussion; and a new instructional unit,
“Web Service Publishing”, is now pa
rt of the product’s Learning Materials. Both items are available
through links on the Windows Start menu at Start / All Programs / IdeaBlade DevForce / Documentation.

Happy publishing!

Tech Tip: Asynchronous Queries

L
evel 300

DevForce Professional

April
25,
20
06

DevForce now supports asynchronous queries. An asynchronous query is a query that runs in the
background on a separate thread while the user continues his/her current work without interruption. One
version of asynchronous queries supports the abil
ity to repeatedly execute the same query at a specified
interval. This can be used to ensure that a client application is constantly up to date with the most current
relevant data. Any number of asynchronous queries can be carried out simultaneously, limit
ed solely by the
availability of threads on the client machine.

Asynchronous queries are invoked in almost the same fashion as a regular query. In fact, any query can be
executed asynchronously by simply calling one of the PersistenceManager.GetEntitiesAs
ync() overloads.




C#:



// Get the Default PersistenceManager.

PersistenceManager pm = PersistenceManager.DefaultManager;

// This is the query for all orders placed within the last 7 days.

RdbQuery query1 = new RdbQuery(typeof(Order),

Order.OrderDateEnt
ityColumn, EntityQueryOp.GT,

DateTime.Today
-

new TimeSpan(7, 0, 0, 0));

// Register an event handler to be called when the query completes.

pm.GetEntitiesCompleted += new EventHandler(pm_GetEntitiesCompleted);

// Start the executing query.

// when it com
pletes, the pm_GetEntitiesCompleted

// referenced above will be called.

// The token "anyValue" will be returned in the

// GetEntitiesCompletedEventArgs to distinguish

// this async call from any others.

pm.GetEntitiesAsync(q, QueryStrategy.DataSourceOn
ly, "anyValue");




VB.NET:



IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

16

' Get the Default PersistenceManager.

Dim pm As PersistenceManager = PersistenceManager.DefaultManager

' This is the query for all orders placed within the last 7 days
.

Dim q As RdbQuery = New RdbQuery (GetType (Order), _

Orde
r.OrderDateEntityColumn, EntityQueryOp.GT, _

DateTime.Today
-

New TimeSpan(7, 0, 0, 0))

' Register an event handler to be called when the query completes.

AddHandler pm.GetEntitiesCompleted, AddressOf _

New EventHandler(Of GetEntitiesCompletedEventArgs) _

(pm_GetEntitiesCompleted)

' Start the executing query.

' When it completes, the pm_GetEntitiesCompleted referenced above

' will be called.

' The token "anyValue" will be returned in the

' GetEntitiesCompletedEventArgs to distinguish

' this async call f
rom any others.

pm.GetEntitiesAsync(q, QueryStrategy.DataSourceOnly, _

"anyValue")

Tech Tip:

Data Source Extensions

Level 300

DevForce Professional

May 23, 2006

Many IT shops prescribe separate Development, QA, Test, Stage, and Production environments. E
ach
version of the application works its way through a testing gauntlet from the developer environment to the
ultimate production release.

Suppose our application refers to a database data source called “default”. Its
data source key

is “default”.
The appl
ication will use this key at runtime to find a
data source configuration
in the application
configuration file (IdeaBlade.ibconfig).

The data source configuration is very simple for the development environment. The development
deployment puts all tiers on
the PC. The “default” development configuration’s connection string points to
a database on the PC.

The QA environment, on the other hand, has a 3 tier deployment with separate machines for client,
business object server, and database. This requires many c
hanges to the “default” configuration including a
different connection string that points to the QA database. We really need a separate “default”
configuration for QA.

In fact, we need five “default” configurations in the application configuration file.

Th
e
symbolic

data source, “default”, doesn’t change as we cross environments. The business objects
associated with the “default” data source should be indifferent to configuration differences. The executing
environment, on the other hand, has to know which o
f the “default” configuration to use.

DevForce provides data source key
extensions

to help distinguish the five “default” data source
configurations. By convention, the data source configuration name is the data source key name followed
optionally by a dat
a source key extension (with an underscore “_” separating the two).

In our example, the configurations could be named “Default_Development”, “Default_QA”, etc. When the
application launches, it determines its runtime environment and then tells the
Persist
enceManager

to
connect to its data source(s) using the extension to find the appropriate data source configuration
information. If we execute in development, we initialize the PM with “Development” and it adds the
“_Development” suffix to “default”.

If the

PersistenceManager

(and, later, the
PersistenceServer
) cannot find a data source
configuration named “Default_Development”, it will look for one named “default” before giving up.

An example section of an IdeaBlade.ibconfig file is showing below:



IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

17

<rdbKe
y name="Default_Development">


<connection>Provider=SQLOLEDB.1;Integrated Security=SSPI;


Persist Security Info=False;Initial Catalog=IdeaBladeTest;


Data Source=.</connection>

</rdbKey>

<rdbKey name="Default_QA">


<connection>Provider=SQLNCLI.1;In
tegrated Security=SSPI;


Persist Security Info=False;Initial Catalog=IdeaBladeTest;


Data Source=.</connection>

</rdbKey>

<rdbKey name="Default_Test">


<connection>Data Source=.;Initial Catalog=IdeaBladeTest;


Integrated Security=True</connection
>

</rdbKey>

<rdbKey name="Default_Test_ORACLE">


<dataProvider>System.Data.OracleClient </dataProvider>


<connection>Data Source=Oracle10G/ibnorth; Password=password;


Persist Security Info=True;User ID=sa;</connection>

</rdbKey>

Note that the multipl
e RdbKeys for a single data source do not have to use the same ADO.NET
dataProvider, nor do they have to reference the same database from the same database vendor (providing
the schemas are compatible).

In addition, entities in the PM may map to more than

one data source. The PM will suffix each data source
key name with the same extension.

At runtime the appropriate datasource can be accessed via a call similar to the one below, where the
“datasourceExtensionName” is determined dynamically by the executin
g application.


C#:

PersistenceManager pm =


new PersistenceManager (true, datasourceExtensionName);

VB.NET:

Dim pm As PersistenceManager = _


New PersistenceManager (True, datasourceExtensionName)


Tech Tip:

Checkpointing

Level 200

DevForce Express

A
ug 22, 06

New in DevForce Release 3.2, checkpointing is the local cache equivalent of a database transaction. You
set a checkpoint with the new BeginCheckpoint() method of the DevForce PersistenceManager. Call the
PM’s RollbackCheckpoint() method if you wa
nt to restore the cache to its checkpointed state. Fetches,
modifications, merges, deletions, additions, removals


all are reversed!

C#:

MyPersistenceManager.BeginCheckpoint();

<any intervening sequence of operations affecting entities in cache>

MyPersist
enceManager.RollbackCheckpoint();

VB.NET:

MyPersistenceManager.BeginCheckpoint()

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

18

<any intervening sequence of operations affecting entities in cache>

MyPersistenceManager.RollbackCheckpoint()

Checkpointing makes cross
-
entity undo a snap. It's usually a nas
ty business to track and undo changes
when the user cancels out of a dialog or wizard, especially if there are many different business objects in
play. Now we just set a checkpoint when the dialog begins and turn the user loose. If the dialog ends
happily,

we discard the checkpoint. If the user cancels, we rollback. Either way, it's one call to start and one
call to finish. No bookkeeping required.

We can stack checkpoints with additional BeginCheckpoint() calls. Each subsequent RollbackCheckpoint()
undoes
the most recent checkpoint. We can cut back the stack by calling RollbackCheckpoint(
count
) where
"
count
" is the number of checkpoints to rollback. Both overloads return the remaining checkpoint depth.

The RollbackCheckpoints() method rolls all the way back

while ClearCheckpoints() wipes the checkpoint
slate clean. ClearCheckpoints() is kind of like “commit” in that we are accepting the present state of the
entity cache. But take care: our pending changes are still in the cache; they won't become permanent u
ntil
we save them to the database!

Note also that the PersistenceManager's Clear() and SaveChanges() methods call ClearCheckpoints()
automatically before proceeding with their respective tasks.

Checkpointing is lightweight. A checkpoint session records ch
anges to the cache
-

not images of the cache.
Clearing checkpoints to accept changes is virtually instantaneous; rollbacks, which are comparatively rare,
are very fast.


Tech Tip:

Concurrency Checking with the SQL Server
Timestamp

Level 200

DevForce Expre
ss

Aug 8,
20
06

DevForce applications can use the SQL Server timestamp data type for database concurrency control. The
SQL Server timestamp column is especially appropriate in environments where data tables could be
updated by both DevForce and non
-
DevForce

applications.

The SQL Server
timestamp

data type is a binary number maintained by the SQL Server
engine. Don't confuse it with the SQL Server
datetime

or the
SQL
-
92 standard
timestamp
. The SQL Server datetime conforms to the SQL
-
92 timestamp standard for

representing real world dates and times. The SQL Server timestamp has nothing to do
with time; it is actually a sequential counter used by SQL server to stamp updated records.


Here is what SQL Server Books Online says about it:


The SQL Server timestamp
data type has nothing to do with times or dates. SQL Server
timestamps are binary numbers that indicate the relative sequence in which data
modifications took place in a database. The timestamp data type was originally
implemented to support the SQL Server

recovery algorithms. ... Never use timestamp
columns in keys, especially primary keys, because the timestamp value changes every
time the row is modified.

While the SQL timestamp is useless as a measure of time, it serves perfectly as an optimistic concur
rency
column in a table mapped to a DevForce business object. SQL Server (re)sets a timestamp column value
whenever the record is saved and we don't have to lift a finger to make that happen. In fact, we couldn't if
we

wanted to because a timestamp column
is read only.


Optimistic Concurrency


DevForce optimisitic concurrency checking depends upon our ability to detect if a single column of a table
IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

19

record has changed since we last fetched it.


When we attempt to update an existing record in a table with a t
imestamp concurrency column, we
compare the original timestamp of our proposed record with the timestamp in the current database record.
If they are the same, no one has changed the record since we fetched it; our update can be saved.


If the timestamps di
ffer, we know that another user updated this record while we were changing our copy
of it. There is a conflict between our changes and that other user's changes
-

a conflict we should detect and
resolve. DevForce will reject our update attempt and raise a
concurrency violation exception for our
application to handle.


Using a Timestamp Property in a DevForce Application

We declare an entity's concurrency column in the DevForce Object Mapper (OM). There are four steps to
making a timestamp column serve as th
e concurrency column.

1.

Select the timestamp column's property name in the "Concurrency Column" combo box in the
"Class" tab.

2.

Check the timestamp property's "Read Only" checkbox in the "Simple Properties" tab.

3.

Change its "Access Modifier" to "Protected".

4.

Change its "Source Access Type" to "Read Only".

Steps #1 and #4 are essential. The other two steps are merely very good practice.



1. Set the Concurrency Column

The timestamp column's property name is "TestTS" in this illustration.


IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

20

2. Check the "Read Only" Box


Our application should never set a column designated as the concurrency column. In the case of a
timestamp column, we couldn't save a changed value ev
en if we wanted to. Therefore, the associated
property should be configured to generate a "Read Only" property, a property with a get method but no set
method. We configure it as a such by checking the "Read Only" checkbox.


3. Set the "Access Modifier" to

"Protected"


We really don't want anyone to see this property either. A timestamp is not a true time value and displaying
it would only confuse people. We should change the "Access Modifier" to "Protected" which will make it
invisible outside the class. T
he DevForce persistence layer has no trouble finding it.


4. Set the "Source Access Type" to "ReadOnly"


We've said repeatedly that the SQL Server timestamp column is read only. Haven't we taken care of that
already with steps #2 and #3?


Nope. Steps #2 an
d #3 govern the routine visibility of the timestamp in our client application. But our
application could have changed the data column value by some means other than through its associated
property.


Therefore, in the absence of contrary instructions, the D
evForce persistence layer tries to set the timestamp
column when it attempts a database update. We have to tell the persistence layer not to do that by setting
the timestamp column property's "Source Access Type" to "Read Only" as shown here.



Catching Concurrency Violations


There are myriad reasons to be ready for a breakdown in the save process. We have just added another one
to the list by engaging optimisti
c concurrency checking; the DevForce persistence layer will now check for
concurrency violations and throw exceptions when it detects them.

Accordingly, all
SaveChanges

method calls should be encapsulated within a try
-
catch block that catches
a
Persistence
ManagerSaveException
. The following code sample shows a primitive catch block
that displays the exception message when the save fails for any reason, including a concurrency violation.

C#:

SaveResult result;

try {


result = mPm.SaveChanges();


M
essageBox.Show("Changes saved");

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

21

} catch (PersistenceManagerSaveException pMException) {


MessageBox.Show(pMException.Message);

} catch (Exception ex) {


MessageBox.Show(ex.Message);

}

VB.NET:


Dim result As SaveResult

Try


result = mPm.
SaveChanges()


MessageBox.Show("Changes saved")

Catch pMex As PersistenceManagerSaveException


MessageBox.Show(pMex.Message)

Catch ex As Exception



MessageBox.Show(ex.Message)

End Try

That’s all there is to it! Look at the “Handling Concu
rrency Conflicts” tutorial in the "Intermediate Topics"
section of the DevForce tutorials collections to learn more about managing concurrency.

Concurrency in Master/Detail Relationships

Level 400

DevForce Express

February 2, 2007

What is the best way to
detect concurrency violations in master / detail relationships?

An Example

Here's a sad tale of Orders and OrderDetails

gone bad:

1.

Abby creates an Order with three OrderDetails, (1a), (1b), and (1c).

2.

Abby saves the Order and its details.

3.

Abby goes to lunch
.

4.

Bob picks up the same Order and changes its details, adding (1d) and deleting
(1b).

5.

Bob saves his changes.

6.

When Abby returns from lunch, she

still has the original Order and details in
her

cache;

7.

Abby continues working on details (1a) and (1c) but does
n't touch (1b) or the
Order itself.

8.

Abby saves her work.

Her save will succeed. She won't hear a peep from the database or DevForce. There is no
concurrency violation because Abby's changes to (1a) and (1c) are independent of

Bob's
work on (1b) and (1d).

This is not good. Abby will not know that Bob has changed the Order. The order Abby
thought she created is not the order stored in the database. Abby, Bob, or the customer
are in for an unpleasant surprise.

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

22

Dependency Automation

Folks often wonder if DevFo
rce can detect the problem and signal a concurrency
violation. DevForce "knows" about the relationship between Order and its OrderDetails.
Perhaps it should infer the implications of that relationship.

In fact, DevForce won't detect the problem and should

not draw any conclusions about
the relationships among the entities.

We begin to see why when we observe that few "master / detail" relationships are as
strong as the one between an Order and its details. For example, Customer has a "master /
detail" rel
ationship to Order. We usually don't mind if Abby and Bob make changes to
separate orders of the same customer. So how is that different from Abby and Bob
changing separate details of the same order?

If you are a UML junky, you know to classify these two
relationships differently. The
Customer / Order relationship is an
"Association"
; we say that a customer
"has
orders"
. The Order / Order relationship is called a
"Composition"
; we say that an Order
"is made up of"

its OrderDetails". "Has a" is not as stron
g as "is made up of".

DevForce object mapping doesn't distinguish among the types of relationship. Some
other mapping products allow you to make this distinction. Is DevForce deficient in this
respect? Should we enable marking the "Order / OrderDetail" re
lationship as a
"composition" and enforce the implications?

We've certainly thought about it. It isn't technically daunting; relationship marking is easy
and cascading inserts, updates, and deletes isn't much harder. But experience teaches us
that the "imp
lications" are not as clear as they seem. For example, we generally don't
worry when two users work on orders for the same customer; but sometimes we do. The
customer could have a credit limit. There could be a business rule that requires senior
management

approval when the sum of all order totals exceeds a threshold.

Should we say that Customer / Order is a composition too and prevent simultaneous
changes by multiple users to any of a customer's orders? That may not fly in the real
world. And there is no
telling where to stop once you start locking up the object graph
with composition constraints. What if the order total threshold changes? Maybe we better
lock up that one. How about the customer's headquarters address? There could be sales
tax implications
; I guess we should lock that up too. Soon no one can do anything for fear
of some dependency somewhere.

We've chosen to stay out of your way. We think you should decide your own business
rules and how to enforce them by writing code for the purpose.

Whi
ch is why we get that question at least once a month: how do I write the code so that
orders and their details are treated as one thing?

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

23

"Root Entity Marker"


Suppose we're certain that any change to either the order or any of its details is a change
to th
e entire order. We'll agree to deal with the nuances of customer credit limits another
way. Meanwhile, we want the application to enforce the integrity of the order with
respect to its details.

I suggest a simple expedient: whenever we save changes to an
OrderDetail, we save its
Order too. Of course we can only save entities that have been changed so we'll have to
mark the Order "dirty".

We can generalize the problem and its solution. Whenever we detect a network (AKA, a
graph) of objects which should be
treated as a single unit, we should (a) identify the
"Root Entity", (b) save the root entity when saving a change to any object in the graph ,
and (c) ensure that we save the combined order changes in a single transaction.

Order is the "Root Entity" in ou
r example. Let's reexamine the story of Abby and Bob,
picking up at the point when Bob saves his changes.

He didn't touch the Order object but the application marked it "dirty" anyway and saved it
along with the addition of (1d) and the deletion of (1b).
Abby's cached copy of the Order
is no longer "current" with respect to the database. When she tries to save her order detail
changes, the application marks her order dirty and tries to save it along with her changes
to (1a) and (1c).

This time she gets a
concurrency violation. Although Abby's and Bob's changes to order
details did not collide
-

they worked on different OrderDetail objects
-

Abby's modified
order no longer matches the order in the database
-

the one saved by Bob. DevForce will
recognize a c
oncurrency error on the order and the transaction will fail.

How to Dirty the Root Entity


It is easy to "dirty" a DevForce entity even i
f it was previously unmodified:

C#:

public static
Entity

EnsureModified(
Entity

pEntity) {



if
( pEntity.RowState ==

DataRowState
.Unchanged ) {



( (
DataRow
)
pEntity ).SetModified();


}


return
pEntity;

}

VB.NET:

Public Shared Function

EnsureModified
(
ByVal

pEntity

As

Entity

)
As

Entity



If

pEntity.RowState =
DataRowState
.Unchanged
Then



CType
(pEntity,
DataRo
w
).SetModified()


End If



Return

pEntity

End Function



IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

24

When to do so takes a tad more programming. A full code sample wouldn't fit in this tip (contact us for it) but
we can benefit right now from a sketch of the primary scenario.

1.

The application tri
es to save Abby's OrderDetails.

2.

DevForce raises its SavingEvent.

3.

The SavingEventArgs provide a list of entities that are about to be saved.

4.

Your SavingEventHandler calls each listed entity's Validate method.

5.

The OrderDetail Validate method first validates

the detail.

6.

It next passes the parent Order to EnsureModified().

7.

It adds the Order to the list of entities to save.

8.

The Order itself gets validated.

9.

The SavingEventHandler returns without validation errors.

10.

DevForce saves the Order and the changed OrderD
etails.


User Experience


Remember that Abby was at lunch when Bob saved his changes. Abby returned and spent
fifteen more minutes working on the details before trying to save. Thanks to our new
logic, the application detected a concurrency violation and t
old her "Sorry Abby, I can't
save your work."

Abby is not happy. Actually, she is furious. If we're lucky, she turns her ire on Bob.

Of course it is really our fault. Bob didn't know that Abby was working on the order and
Abby didn't know that Bob had ta
ken over.

We might try to help her reconcile the differences
-

and perhaps merge her changes into
Bob's. I think this is an exercise in futility. We'll burden our application with crushing
complexity while doing little to improve Abby's mood. We should co
ncentrate instead on
preventing the problem in the first place.

I recommend that you combine the "Root Entity Marker" approach with a "Root Entity
Reservation" system.

Root Entity Reservation


We could require a user to reserve (or "check out") the root
entity before she begins work
on it or any of its parts. Accordingly we begin by adding a "ReservedByUserId" column
to the Order table.

[Aside: this is just one implementation. Maybe we can't change an existing table, in
which case we could create a new "
OrderReservation" table. "OrderReservation"
becomes the "root entity" in our drama with Order and its OrderDetails in supporting
roles.]

IdeaBlade DevForce Developers Guide
,
v.
Error! Reference source not found.


Object Persistence

prettybadelynge_a82ec489
-
756c
-
49d3
-
aa13
-
50b55b4e0e61.doc
Copyright © 2006, IdeaBlade, Inc, all rights reserved

25

When Abby first saves her new Order, the UI stamps the ReservedByUserId with her
user id. Then Bob looks at the Order
in a list of pending work. He sees that Abby has
reserved it. The application won't let him edit it.

Abby returns from lunch. She still owns the order. She makes her changes, saves her
work, and releases her reservation. Now Bob can take over if he still
wants to do so.

Let's suppose he does. The UI stamps the order with his user id and attempts to save it.
Had the save succeeded, the UI would have opened the "order graph" for him to edit. As
it happens, Charles from across the hall reserves the order a s
plit second ahead of Bob,
causing Bob's save to fail. Bob's UI refreshes its cached copy of the order so he can see