Revision History


Version v3.9.5.X\v3.8.9.X

Please see ChangeLog.txt for the list of changes included into these minor updates.

Version 3.9.5

Release notes:

This version of DataObjects.NET is stable.

Migration from v3.8.X\v3.9.1 to v3.9.5 shouldn't lead to any problems - new version fully supports (upgrades) v3.8.X database schema, as well as its serialization format. But not vice versa - you can't switch back to any previous version with ease after migration to v3.9.5!

Support Forum Archive is removed from .HxS help file, but it is still available in .Chm help file.

What's new

Query Profiler and query profiling API (IDbCommandEventWatcher, DbCommandEventWatcherService, etc.). Detailed description of Query Profiler will be shortly published here:

DataSource control and BindingSource component are added. Both of them are used in a data binding scenarios, but the first one is intended for the Web environment, and the second one - for Windows Forms.
Detailed description of these new features will be shortly published here:

BindingManager component is re-implemented according with user requirements in our Support Forum.
Detailed description of changes will be shortly published here:

DataContext class (lightweight version) is added to DataObjects.NET.UI namespace.
Please see for details.

ValidationService code is added to DataObjects.Net.

Access validators are implemented.

Generators (table-based) are now used to provide new ID values instead of autoincrement comumns - this lead to serious changes in our persistence engine (now DataObjects.Net takes care about correct persist sequence), but on the other hand you can access the Key (ID) of DataObject instance without making it to persist itself. This resolves many "famous" problems, e.g. with unique indexes.

New samples: Demo_BindingManager (it replaces Demo_BindingManager_Win), Demo_FormsBinding and Demo_WebBinding.

Generic analogue of QueryResult class is implemented.


MSSQL Persister refactoring. All direct IDbCommand.Execute(DataReader|Scalar|NonQuery) method calls have been redirected to Persister.Execute(DataReader|Scalar|NonQuery). This was made for IDbCommandEventWatcher services implementation.

Demo_BindingManager_Web sample is removed. New BindingManager doesn't support web data binding, but new DataSource provides all the features needed here

ConnectionUrls like "mssql://someHostOrIp:somePort/DatabaseName" containing port specification are now supported.


All the fixes made in v3.8.9 release in v3.8.X branch are merged into this version. The complete list of these fixes can be found below.

Old style Permissions had not be marked as "Inconsistent" during deserialization. As a consequence an exception handling cycle has been performed each time an object with old-style permissions loaded. After the fix "Inconsistent" permissions will be updated in the database at the next persist operation.

Session.InnerPreload()generates queries without any condition in where clause in some cases - in fact this was leading to locking of the whole doDataObject table

MSSQL Persister doesn't check "Key.ID>0" condition in FetchInstanceColumns method before SQL command text generation

Schema property was absent in Configuration.FromElement and ToElement methods (.Net 2.0 only)

Minor fixes in MSSQLExtractor

Foreign keys information is extracted improperly in case of presence of several schemes in the database

Foreign keys for reference fields cannot refer on the native partitioned table. Therefore such keys should refer on doDataObject table

It was possible to create two instances of some ITransactionEventWatcher service per Session if the GetService method has started the first transaction related to this Session

Unexpected access to a Session while updating reference field or DataObjectCollection in offline. The problem cause is Contains method call on a paired collection that is not loaded.

Key fields were not correctly supported in OQL expressions.

Query Profiler delivers no result set

Bug in PrimitiveFieldRelationDescriptor

Offline subsystem is broken (appears in v3.9.5 build 6379, fixed in v3.9.5 build 6474)

Bug with serialization of ValidationException

SecurityException on transaction commit in versionizing mode

Several performance-related fixes

DataObject.Lock() functionality has been broken

Stack trace truncation for any Exception thrown from parameterized OnCreate method

Lack of AccessCheckPoint control in parameterized OnCreate method.

DataObjects v3.9.x does not properly detects version conflicts on ReadCommitted isolation level

Foreign key violation on removing some object that contains non empty symmetric collection.

"Lucene query ordered by FullTextRank"

Catching exceptions thrown in OnCreate

NullReferenceException in MSSQLPersister


Version 3.8.9

What's new

AccessToSessionFailed event is implemented in Offline layer. Now user is capable to provide an alive remote Session instance instead of a corrupted one.

SupportsUpgrade property is added to DriverInfo.


Parameter setup code was partly extracted to separate the method from Persister classes to Utils

TypeModifier feature is implemented for Offline layer

A way an ObjectSet deals with a remote Session is refined.

Oracle driver has been updated - now it supports top condition in queries that in conjunction with other changes makes it faster.

AccessControlList unpacking speed was dramatically increased. Applications that widely use DataObjects.NET security system will notice significant performance impact.

It is possible now to deserialize ObjectSet without having remote Domain accessible (in this case ObjectModel is stored at ClientSideCache)


SystemFieldNames check in ObjectModelBuilder

Erroneous collection query translation ("Select Product.Items instances where {$rootOwner.ID}=...")

ORA-12704 error while building domain in 3.8.8

Enum fields with [Flags] are not properly extracted from the database

Shared DataService is created twice for same Session

Field.OfflineTypeModifier property was not being serialized

Interface implementation check is added to ProxyBuilder.BuildCreateDataObjectCollectionInstanceClause method

Getting rid of unnecessary right joins in M:N relations

Problem with ID in OQL

Getting rid of unnecessary nested selects on [oqlAlias].[ID]

BlobField with applied Nullable attribute returns new byte[0] instead of null

Minor fixes in Domain.DetectUpgradeIsAvailable method

Domain.Environment property throws NullReferenceException

Possibility to get Session with corrupted data under high concurrency (buggy exception handling inside Session.Persist)

Unable to declare DataObject descendant indexer

SQL Server 2005 requires scale & precision properties to be explicitly set for parameters with decimal DbType

An attempt to register Domain in ClientSideCache can cause a failure due to concurrency problems

Impossible to turn off storing proxy assembly to file

It is possible to fill GlobalCache with not committed data

Unexpected access to Session while updating reference or DataObjectCollection property in offline. The problem cause is Contains method call on a paired collection that is not loaded yet.

Negative IDs in query

Transaction management bug

"OnRemove is called twice"

Deserialization of fields with [PairTo] attribute

Bug with TransactionRequiredException

Problem with Snapshot isolation level in Firebird driver

"Serialization and deserialization of ACLs"

"Serialization of offline DataObject"

It is now possible to use NamingManager.ShortenIdentifier method concurrently


Version 3.9.1

Release notes:

This is beta version of DataObjects.NET. It is quite stable - it passes all the tests ported from v3.8.X branch, as well as new ones, but we don't recommend using it in production environment. During nearest 2 months we plan to gather customers' feedback on it and change its status to stable. The most current stable version is v3.8.8.

This version supports only SQL Server 2000\2005; upcoming v4.0.X will initially support only this RDBMS as well. Currently we don't plan to develop drivers for other RDBMS in v3.9.X branch, since v4.0 branch should bring even more dramatic changes to RDBMS drivers layer - we want to save the resources and focus on it now.

v3.9.X and v3.8.X branches will be maintained in parallel. Latest stable builds in both branches will be available for all our customers.

Migration from v3.8.X to v3.9.1 shouldn't lead to any problems - new version fully supports (upgrades) v3.8.X database schema, as well as its serialization format. But not vice versa - you can't switch back with ease to v3.8.X after migration to v3.9.1!

What's new

Partitioning support is implemented. Partitioning allows distributing the data of a single table across several partitions according with your own rules. There are two partitioning modes - emulated and native:

Emulated partitioning is RDBMS-independent; it implies that DataObjects.NET creates table for each partition, and a view uniting the partitioned data across several tables.

Native partitioning is based on native partitioning features of RDBMS. Database schema stays almost the same in this case, but DDL statements generated for partitioned table creation \ updates include partitioning information.

DataObjects.NET currently supports 4 types of partitioning:

Range partitioning - selects partition by determining if the partitioning expression evaluation result is falling into a given range

List partitioning - the partition is selected based on partitioning expression result matching one of a set of discrete values

Hash partitioning - partition is selected based on the value of hash function applied to the partitioning expression evaluation result

Object type partitioning - selects partition by determining if the object type matches one of a set of object types

Please refer to DataObjects.NET Manual ("Advanced features \ Partitioning") and new Demo_Partitioning for details.

Key struct is added - it will replace long ID in future versions.

All references are internally stored in Key struct (currently it stores both ID and TypeID, when TypeID is already known).

There is a special DomainDatabaseOption making DataObjects.NET to persist TypeID along with any reference (a special column is created for it). This allows to use partitioning by TypeID of any reference, and moreover, optimize fetches (DO already knows actual type of object on fetching a reference to it).

DataObject.ID, DataObject.TypeID and all similar properties and methods accepting long id, long[] ids as parameters are marked as [Obsolete] - you should start using their analogues accepting Key struct. All such properties and methods will be completely removed in v4.0.


Domain configuration is now stored in DomainConfiguration class. Domain.Configuration property refers to DomainConfiguration instance attached to the Domain.

DomainConfiguration class is non-MBR, serializable type. All other objects reachable from it are also non-MBR serializable objects. So you can serialize \ deserialize DomainConfiguration objects, as well as pass them across AppDomain boundaries in serialized form using .Net Remoting (they aren't MBR objects)

In particular, this touches Culture and CultureCollection classes, that were formerly MBR objects

It is easy create the clone of Domain now: just create one more Domain with the same DomainConfiguration object

It's easy to clone DomainConfiguration object (e.g. to modify the configuration) by invoking its Clone method

.Net 2.0 specific feature: DomainConfiguration can be imported from and saved to ExeName.config \ Web.config files (any configuration file). See FromElement \ ToElement methods of Configuration class for details.

Above features open the opportunity to develop tools that are fully independent from the actual Domain configuration, such as upcoming Oql.exe (query profiling tool) and Upgrade.exe (sequential upgrade tool + advanced upgrade API). Any of such tools will be able to build fully functional Domain object by using new configuration API -  e.g. it may simply load the configuration file from the current folder, or use command line parameters to locate it. Formerly it was impossible to do the same without additional coding.

Database driver architecture is unified and updated:

Full support for database schema names. Now DataObjects.NET generates fully qualified database object names everywhere.

New version uses unified Persister, PersisterForCollecton and UpdateActionTranslator for both regular and Versionized (see DomainDatabaseOptions.EnableVersionizing) mode. Formerly different set of these classes (but handling the same set of tasks) was used in these two different modes.

ObjectModel and DatabaseModel are significantly changed:

ObjectModel is updated for Key struct support

Both models are extended to support partitioning

We added a set of additional classes (~ one per each Field class) describing relationships between DatabaseModel objects and ObjectModel objects.


All the fixes made after v3.8.8 release in v3.8.X branch are merged into this version. The complete list of these fixes will be published on upcoming v3.8.X update.


Version 3.8.8

What's new

Semi-automatic database upgrade code is ported from 3.9 branch
See for details. Currently there is no "official" documentation on this feature, but Manual shipped with v3.9 will describe it.


MaxDB driver is considered as obsolete. We won't support this RDBMS further, although it still exists in v3.8.X branch

Domain.ObjectModelGuid property is removed: use Domain.Guid instead

Domain.ProxyAssemblySuffix property is removed: use Domain.Guid instead

Domain.Drop static method is added. It "marks" Domain as unusable with the aim to create a new one with the same Guid in the same application domain

Domain.Build improvements:

In Skip mode extractor no longer extracts all tables but only system ones

In SkipXXX modes cached proxy assembly is no longer recompiled if it exists


CLS-incompatible types (SByte, Uint16, Uint32, Uint64) are now:

Fully supported by MSSQL driver

Fully supported by both Oracle drivers

Supported by Firebird driver (except UInt64)

Prohibited in Microsoft Access & MaxDB drivers

Tables & views naming rules are changed in MSSQL driver. Now table & view objects are named as dbo.objectName instead of <user>.objectName. Automatic conversion of table and view objects from <user>.objectName to dbo.objectName is implemented.

SmallDateTime is excluded from supported data types in both Oracle drivers


EnumField constructor now allows to create EnumField instances dynamically

Byte data type is remapped from DbType.Byte to DbType.Int16 in NativeOracle driver

Adapter's DoCollectionTranslator & VtCollectionTranslator behaves improperly in Update method

"ID field in index"

"InvalidCastException in QueryBase.ExecuteArrayI method"

"Unexpected Persist in UniqueValidator.Validate"

"NullReferenceException in BindingDescriptor.PropertyType"

"BindingManager with string indexers ineffective on .Net 2.0"

An issue with Type criteria usage in Lucene Indexer is fixed

"Lucene indexer is going crazy"

UpdateActionTranslator exceeds identifier name length limit

DataService registration problem: DataService proxies from already loaded proxy assemblies were attempted to be registered as regular DataServices in repeated Domain.Build() call.

Incorrect Performance Counters removal when AppDomain is unloading

Wrong ObjectModel comparison in ObjectSet.CreateObjectCopy method

Default constraint existence check is added before its deletion (MSSQLUpdateActionTranslator)

SessionBoundObject.DisableBusinessLogic / EnableBusinessLogic methods availability check

Several fixes related to persist & fetch behavior of Single & Double values from appropriate number ranges in Oracle drivers

Significant code refinements in: SessionCache, LuceneFtIndexer, both Oracle and Native Oracle Drivers.


Version 3.8.7

What's new

Support for generic methods in Offline layer

IPager interface is added

Static Session.ExecTransactionally method is added to use instead of instance method with the same name when working via .Net Remoting.


.Net 2.0 Samples are now built for Visual Studio 2005 with Web Application Projects. You can download the required update here:

Domain.Guid & Domain.ObjectModelGuid handling behavior is improved:

Domain.ObjectModelGuid returns Domain.Guid

Domain.Guid is set to Guid.Empty by default

If Domain.Guid is manually set, ProxyAssemblyName is "ProxyAssembly_"+Domain.Guid, otherwise it is "ProxyAssembly"

It is possible to utilize multiple domains on client side.
You need to manually set
Domain.Guid to every domain in this case.

Default IDbCommand.CommandTimeout set to 60

Resource handling improvements ("using" statement are applied to all places where IDbCommand, IDataReader, etc. are created and used)

Naming rules for ProxyAssembly.dll source code are changed.
Now all names of method parameters and generic types starts with the '_' character, which is followed by parameter/generic type name given in base class. This allows us to preserve parameters/generic types semantic, as well as avoid naming conflicts inside proxy assembly (non of internally used symbols in proxy assembly starts with the '_' character).


Lucene full-text driver does not utilize TypeID when executes full-text queries

The object which refers to another one is not updated after Synchronize, if referenced object is removed on server

ApplyChanges does not download the new objects entirely (delayed event notification for correct ObjectSet merging is implemented)

Wrong BlobField.SqlType (SQL Server 2005, binary fields)

Incorrect ITransactionEventWatcher.OnTransactionCommit behavior

Divide by zero exception in GetEffectivePermissionSet

ObjectSet.RemoveObjects disables method call registration

Wrong MSSQLUpdateActionTranslator behavior for AnsiVarCharMax, VarCharMax, VarBinaryMax-type properties with applied [Length] attribute

Offline.DataObject.Reload() method does nothing if object is changed (DataObject.IsChanged==true)
ApplyChanges is very slow on large ObjectSets

IndexOutOfRangeException on ApplyChanges

[ToOffline] attribute together with [PairTo] attribute

BindingManager and Nullable type

[TypeModifier] attribute + Offline.DataObject leads to an exception

Automatic indexing of DataObject properties inside struct fields

Workaround for invalid System.Type.FullName result for arrays like int[,,][,] is implemented in ProxyBuilder - in this case FullName returns System.Int32[,][,,]

Improper overriding of generic methods

Minor fixes related to proxy assemblies handling

Minor updates in MSSQLExtractor code

ObjectSet.RemoveObjects no longer works as expected. ObjectSet does not remove online objects when ApplyChanges is called.

.Net Remoting & QueryPager

Minor update in BindingManager.SetIndexedProperty method

BindingManager with string indexers is ineffective on .Net 2.0

LoadProperty bug (Offline layer)

Firebird driver optimization: question marks are used in SQL queries instead of named parameters.

Removed dependency parent leads to an exception, if cached

Invalid references appear after ObjectSet.ApplyChanges call without UpdateOption.Refill option turned on

Unexpected NullReferenceException

ApplyChanges does not download new objects entirely (partially fixed)

ObjectSet.Merge method is not reentrant

DataObjects with internal properties are handled improperly

Memory leak in Query.Execute

A remote ObjectModel instance has no reference to Domain

Using property path in DataObject.GetProperty

DataObject.PropertyContentChanged is called for empty collection

Security checks are utterly slow with huge amount of data

DataObjectCollection.ToOffline() bug

Offline dependency to DataObjects.NET Lucene full-text driver

TransactionController.CommitOrRollback does not set Session.OutermostTransaction to null

ObjectModel with DisallowGreaterThan \ DisallowLessThan validators deserialization problem

Determining whether ProxyAssembly.dll is valid.

Scheduling DataService method invocation from ObjectSet

Removal doesn't work for [LoadOnDemand] + [Contained]

Trying to use a parameter when none exists

Error on loading external driver

Unhandled SocketException occurs when using ClientSideCache. Only ObjectSet.ApplyChanges() can throw SocketException if remote Domain is dead now.


Version 3.8.5

What's new

Generic methods support (proxy code can be built for  them now,  so [Transactional(TransactionMode.Disabled)] attribute  is not obligatory)


Session.CreateObject<T>(string name, params object[] initParams) where T: DataObject and ObjectSet.CreateObject<T>(string name, params object[] initParams) where T: DataObject are both renamed to CreateNamedObject

Domain.Build() in SkipButExtractAndCompare mode throws DomainUpdateIsBlockedException if the new database schema differs from the current one

Referenced ObjectModel.Type is added to ReferenceField


ArgumentException is now fired instead of InvalidCastException when setting null value to non-nullable property

[AutoFixup(AutoFixupAction.Block)] does not work on a paired ValueTypeCollections

Can't retry a Domain.Build after exception

TransactionController.CommitOrRollback throws an exception

NullReferenceException on Domain creation

A problem with creation of offline objects having no offline analogues

Type conversion issues in a SetProperty method

Offline client crashes on Windows XP Pro installed on FAT32 file system

DotLucene and DataObjects.NET v3.8 (.NET 1.1) release causing errors (the reader is closed before opening writer)

BindingManager and struct fields

BindingManager.Eval and indexed properties

Empty TimeSpan and BindingManager raise an exception

Invalid calls of String.Format in the ProxyBuilder class

Domain.RegisterTypes() tries to load types from a proxy assembly lying in memory that was built during previous unsuccessful Domain.Build()

[ShareDescendantTable] and indexes

ASP.Net application cannot be accessed under several URLs when Lucene full-text search driver is used.  For non-Mono builds embedded full-text search drivers are not stored now to cache folder before loading. Under Mono it needs to set ProxyAssemblyCacheFolder before FtsConnectionUrl setting

"Key cannot be null." in ObjectSet.ApplyChanges

OnPropertyContentChanged() event never gets fired when DataObjectCollection.Clear() has been called

Database schema update in Perform mode fails when UseForeignKeys option is enabled

Query with QueryParameter.Value==DateTime.MinValue

Session.Preload(ids, fields) throws "Object reference not set to an instance of an object." exception

Clustered index on ValueTypeCollection struct Owner column

Invalid upgrade script for share descendent table usage

Unexpected PrincipalType on Session.User object

View extraction problem

Offline.DataObject.SetProperty works different in a two similar cases

DataObjects.NET, .NET 2.0 build: Session.Invoke(...) method was not able to call suitable CreateObject(...) method

Disabling security during validation

Removing a new offline object causes error in serialization

Error messages when building domain. Now DataObjects.NET checks if DataObject or DataService descendant is abstract.

DataObjects.NET does not inform the developer that DataObjectCollection or ValueTypeCollection descendant is declared improperly

DataObjects.NET never uses cached assembly if System.dll is referenced. The algorithm that checks validity of cached ProxyAssembly.dll is considerably updated.

Greg Fodor's performance patch is reviewed and applied.

Problem which blocked "Embeded DataObjects.NET Lucene Fulltext Search Driver" usage is resolved


Version 3.8.1

What's new

Helper methods for .Net Framework 2.0:









Support for varchar(max)/varbinary(max) database column types is implemented, see new SqlType   enumeration members (SQL Server 2005-specific)


OperationFailedException.ToString() method is overriden to provide more informative output about server-side errors

BindingManager updates:

DataObjects.NET.UI.BindingErrorInfo class is added

DataObjects.NET.UI.IErrorInfoControl interface is updated

ObjectSet.Synchronize method is added


Declaring offline analogue of persistent property which name is  the same as name of some private/internal property in the offline class ancestor caused proxy assembly compilation error (e.g. declaring "Properties" property in the Offline.DataObject descendant)

ObjectSet serialization bug (MethodCallDescriptors are not serialized properly)

Detection of ObjectModel.Type by the offline System.Type

ProxyBuilder builds invalid proxy for generic class parameterized with an array

Problem with DataObjects.NET.Adapter (StackOverflowException when calling Fill method)

NullReferenceException("Invocation target is null.") exception at the server-side instead of one which is real cause of fail

Offline.QueryResult.ItemObjectModelType implementation is incorrect

FirebirdPersister.BuildQueryCommandText() method does not use the 'top' parameter

Offline.UpdateOptions.Refill and Offline.UpdateOptions.CheckVersionsOfChangedObjectsOnly options are not processed correctly

"ApplicationInstance problem"

DataObject.PackFastLoadData/UnpackFastLoadData methods updated in order to fix "Illegal FastLoadData" exception

"A Severe Error has Occurred on the Current Command" (correct exception replacement)

"Invalid product key"

Savepoint.HasChanges() method logic is updated

Problems with generics in offline layer

Other less important fixes.


Version 3.8


Full support of .Net Framework 2.0 and Visual Studio 2005 final

Separate versions of samples for .Net 1.1 and 2.0 are bundled into installation package

Separate versions of source code for .Net 1.1 and 2.0 are shipped with Professional, Enterprise and Unlimited Editions

Help integration with Visual Studio 2005 help collection

Offline layer:

ObjectSet implements ICollection interface now

IEditableObject implementation improved

Feature request: "ObjectModel deserialization is too slow"

Full-text indexing & search:

IFtIndexer interface is added

Feature request: "Full-text indexing query optimization"

Feature request: "IFtObject implementers should be able to not generate FtRecords"

Support for Lucene Index Writer settings in the FtsConnectionUrl

Indexing & unique constraints:

UniqueValidator is fully implemented

[Index] attribute behavior is changed: IndexAttribute(string name) constructor version is replaced with IndexAttribute(string fields)

Feature request: "Associate custom info with persistent types and fields."

Tracing support is updated


Generic methods support (generic methods must have [Transactional(TransactionMode.Disabled)] attribute)

"Unable set to null a [Nullable] offline property if it isn't loaded yet"

"QueryParameter - assigning null value"

"BindingManager fails if no offline model defined"

"OQL translation bug on SQL Server 2000 when using "require" (NoHyphens bugfix)"

DataObjectCollection paired to a property in [ShareDescendantTable] type operates improperly

"Remoting + ToOffline() = Exception" (Validators are not deserialized because internally stores IComparable instance reference)

".Net 2.0: Field.CreateNullSubstitution returns null for Nullable<...> fields with [Nullable] attribute applied."

"Problem with UniqueValidator"

"ConnectionString property has not been initialized"

"If a graph of objects serialized with FormatterAssemblyStyle.Full option it then can't be deserialized by another version of DataObjects.NET assembly". Now all DataObjects.NET type references are resolved to the currently loaded assembly.

"DataObjects.NET and VS 2005 RC1"

"DataObjects.NET sources does not compile on VS 2005 final"

"Updates in UI controls bound to Offline.QueryResult"

"Problem with overriding Offline.QueryResult"

QueryResult containing new Offline objects (with negative identifiers) is now transparently updated after ApplyChanges invocation, i.e. all old negative identifiers are replaced with the new positive ones.

"Offline.QueryResult contains a bug in item type detection, it takes place when Offline model is incomplete or absent."

Unnecessary DB schema updates in Perform mode with Firebird driver. The cause of error is the slightly different behaviour of 1.6 and 1.7 versions of Firebird.NET Provider, so DB schema extractor was working improperly with new version.

"SerializationException in Offline"

"DateTimeField bug"

ObjectSet.ApplyChanges fails when ObjectSet.Session==null and new Offline.DataObject instance created

"Database schema update fails after adding a culture / translatable properties"

"Now for .NET 2.0.50215 (beta 2) permissions checks are skipped."

Other less important fixes.


Version 3.7

What's New

New features of .NET Framework 2.0 are supported:

Generics: you can use fully parameterized generics (or their descendants) as persistent entity types

Nullable types: you can use nullable types (of supported .NET types) as types of persistent properties. It isn't necessary to explicitly apply [Nullable] attribute in this case.

UniqueValidator is added

IDataObject[] QueryBase.ExecuteArrayI() methods are added - they allow to properly cast results for queries like "Select IMyInterface instances" (ExecuteArray() always returns DataObject[] for such queries, so its result can't be cast to an "array of interfaces" type).

Savepoint.HasChanges(...) methods are added

A set of debug\trace-related properties and methods is added:

ShortenedName in ObjectModel.Type and ObjectModel.Service classes

ToDebugString(), ToString() - in DataObject, DataService, DataObjectCollection and ValueTypeCollection classes

Note: tracing support isn't fully implemented yet. Don't use trace-related classes from DataObjects.NET.Diagnostics namespace


Now it's possible to assign temporary names to newly created online and offline instances to get them associated with each other. Use ObjectSet.RegisterObjectName and Session.RegisterObjectName methods to associate offline entity with online one.  
See (foreach iteration problem mentioned here is also fixed)

ObjectSet[DataObject object] indexer is implemented. It allows to find a pair for newly created Offline.DataObject instance in the target ObjectSet after ObjectSet.Merge() operation

Session.Preload method code is updated to enforce optimal execution plan. It was discovered that SQL Server's query optimizer was producing completely wrong execution plan (containing full table scan operation) for some preload queries. Although it was quite rare case (moreover, it looks like it was at least partially random mistake), but this could lead to significant performance impact such on preloads, especially on large databases.

FtField can store array of values now; FtData.Add(...) logic is updated. LuceneFtIndexer is capable of adding multiple values of fields with the same name to full-text index

Principal demands AdministrationPermission only for Name and Description fields now (for other fields it demands OwnerPermission).

Savepoint.UndoActions and MethodCallDescriptors collections became public

Mono support is improved. There are several issues yet because of Mono bugs in SqlCommand and   CSharpCodeGenerator classes.
See for some details

Available Source Code Package is updated


ObjectModelBuilder, ProxyBuilder: fixed indexers (this[...]) handling logic. Indexers are considered as not persistent now.

"[ShareDescendantTable] and indexing the inherited column"

"Problems with parameter conversion"

"Bug in [LoadOnDemand] with struct and no permissions"

"Inefficiency in GlobalCache"

"Rollback not always performed"

"BindingManager.GetBindingExpression() does not work"

"BindingManager.GetBindingManager() does not work"

"ComboBox and BindingManager - problem with enum values"

"Building database on case sensitive SQL Server 2000"

"Savepoint.Rollback() on v3.7"

LockableCollectionBase serialization/deserialization methods are updated to avoid SerializationException when SoapFormatter is used by .NET Remoting.

BoxedGuid comparison operators worked improperly

ObjectSet implementation is updated. It no longer attempts to access some fields of remote Session directly, corresponding properties are used instead.

"MS-Access, ValueTypeCollection with DateTime field fails"

Other less important fixes.


Version 3.6.1

What's New

[ToOfline] attribute is added. All fields marked as [ToOffline(false)] are not accessible in the offline layer at all

IRuntimeServiceEventWatcher interface is added

Schema update SQL script ("SchemaUpdateSQL.txt" file and corresponding part of "DomainBuildLog.txt") is now commented

All items in the files "DomainDatabaseModel.txt" and "ExtractedDatabaseModel.txt" are now sorted alphabetically (so it's quite easy to diff these files)

SessionBoundObject.CreateSecurityDisabler() method is added

ObjectSet.CreateBusinessMethodCallRegistrationDisabler() method is added

Initial content creation (deserialization) is implemented in Demo_DisconnectedSets


A restriction requiring an offline type to declare all fields of the its online analogue is removed. Only type correspondence checks are performed now

Session locking in the offline-related DataServices is implemented. It is safe now to work with several ObjectSets bound to the same Session from multiple threads simultaneously

ObjectSet generation and request handling is optimized (performance improvement)

ObjectSet serialization is improved

If Assembly.GetTypes throws an exception in Domain.RegisterTypes or Domain.RegisterServices, this exception is caught and wrapped into DataObjectsDotNetException with a message containing the name of assembly for which exception is thrown

More informative message is added to all methods of Offline.ValueTypeCollectionImplementation class

Methods of ITransactionEventWatcher interface implementors (DataServices) have TransactionMode.Disabled [TransactionMode] spec. by default

<httpRuntime> section is added to DoPetShop.Web (sample application), mainly to prevent  possible "System.Web.HttpException: Maximum request length exceeded" exceptions in DoPetShop Rempting Client

Few UI-related updates in Demo_DisconnectedSets


Incorrect FastLoadData deserialization problem. No exception is thrown now, and incorrect FastLoadData value is properly updated (all field values are fetched from columns in this case)

A problem with using DataObject property reference in Query

[NotPersistent] attribute inheritance problem ([NotPersistent] attribute isn't inherited for overridden properties)

TrackingService class bug leading to unexpected behavior of TrackingSet class and Offline.ApplyChanges method

Wrong validators and correctors were used on setting a property in the "a.b.c" form

"Removing Roles/Principals throws an exception on ACL clear"

ArgumentOutOfRangeException in Session.Preload

An ability to create a Savepoint manually when at least one Savepoint created by the SavepointController is active

A problem in Offline.QueryResult.DetectItemType method

A problem in ObjectSetRequestProcessor.ProcessUpdateRequest method (content of Offline.DataObjectCollection becomes wrong)

Other less important fixes.


Version 3.6

What's New

A set of available DataObjects.NET editions was changed. The most important part here is that Trail Edition is replaced by Express Edition. Express Edition can be used absolutely free of change, and it doesn't expire in 21 days.

GlobalCache improvements:

Dependency tracking, see

[LoadOnDemand], DataObjectCollection and ValueTypeCollection field are cached; Note that caching works only for fields with default ChangesTrackingMode (ThroughOwner)

New GlobalCache performance counters were added

Transactions performance counters were added

DoPetShop Remoting Client implementation is updated - it's based on the offline layer now. This sample is primary example of offline layer usage in v3.6.


Serialization format for offline DataObjects is updated (GetObjectData is implemented) - serialized data is very similar to the same of online instances now

Offline.Merge implementation is updated. See new MergeOptions description. It is now possible to merge two ObjectSets containing not intersected modifications

Some dependencies of DataObjects.NET.dll assembly from System.Web.dll, System.Drawing.dll and System.Design.dll assemblies were removed

Dependency from Vsjlib.dll is eliminated. DataObjects.NET.Helpers.Compressor now uses Zip compression implementation from SharpZipLib v0.84 (implementation is copied into DataObjects.NET assembly)

IDataObjectEventWatcher.OnDataObjectDeserializeIdentity event is added

[SqlType] attribute is now supported by DateTimeField now, so DateTime fields can be persisted to SqlType.SmallDateTime and character column types now in addition to SqlType.DateTime columns

All drivers now support ConnectionStringSuffix parameter in Domain.ConnectionUrl, so you can specify any string that should be appended to the underlying ADO.NET connection string

AttachDbFile parameter support is implemented in MSSQLDriver

If Domain.RegisterTypes (or RegisterServices) doesn't find any types/services in the given namespace, an exception is thrown now

Installer & documentation updates:

"Not remotable version" of DataObjects.NET.dll isn't shipped with product now.

DataObjects.NET.chm was removed from installer to reduce its size. It can be separately downloaded from this page:

Manual was slightly updated (in particular, "Implementation steps" were added to several chapters)

Other minor updates


"Tracking of newly created objects in ObjectSetRequestProcessor"

"Collection already contains item with ID=-2" (bug in ObjectSet.Merge method)

"ObjectSet.ApplyChanges doesn't raise database errors"

Custom GetHashCode() in Offline object"

"DataObject.UpdateInconsistentData does not work"

"InvalidOperationException in DataObjectCollection.Remove() method"

"Removal of object with contained objects"

"[LoadOnDemand] attribute applied to ValueTypeCollection property"

"[ShareDescendantTable] and ValueTypeCollection indexing"

"Use of DisableInvalidObjectIdentifiers decreases ValueTypeCollection performance"

"Exception with class with derived class and struct fields"

"State of caching of guests role and guest user"

"Information after failed update on server"

"Text search on object properties"

"Indexer property on DataObject" problem

"Changing model dynamically - adding field to base abstract type"

"SQL Server 2005 Table Ordering"

"Oracle driver: Too many open cursors"

"Oracle migration issue"

"MS Access Driver - data type mismatch error"

"MS Access Driver - DateTime default value"

Other less important fixes


Version 3.5

What's New

UpdateActions were completely replaced by MethodCallDescriptors in the offline layer; two new attributes ([BusinessMethod], [OfflineBusinessMethod]) were added to support new behavior. Currently updates made to the ObjectSet are tracked by much more generic way: during the whole lifetime ObjectSet gathers information about all invocations of offline methods marked by [OfflineBusinessMethod] attribute.

This information is stored in MethodCallDescriptor objects (see Savepoint.MethodCallDescriptors property). It's forwarded by ObjectSet to the application server when its ApplyChanges method is invoked, where completely the same sequence of method calls is executed, but on online objects

Offline objects passed as method call arguments are certainly properly converted to corresponding online objects

By doing this, we reproduce the whole sequence of updates made to the client-side ObjectSet on actual business entities "living" on application server - so our BLL code still works only on the server side (offline entities only simulate the activity of server-side objects)

As it was earlier, all changes made to online objects during ApplyChanges operation are transparently propagated to the offline entities on its completion.

Since MethodCallDescriptor is automatically populated when any [OfflineBusinessMethod] is invoked, you can implement your own methods which calls will be considered as an update operation, that should be re-executed on the server side later. E.g. you can implement offline Account.Transfer method as following:

Disable MethodCallDescriptors population (see ObjectSet.DisableBusinessMethodCallRegistration)

Perform actual transfer operation in the ObjectSet (client-side emulation of server-side operation)

Enable MethodCallDescriptors population (see ObjectSet.EnableBusinessMethodCallRegistration)

This approach ensures that:

Application server will receive full information about the operation represented by Transfer method, rather then only an information about property changes made on two Account objects participating in transfer (all low-level methods, such as Offline.DataObject.SetProperty or Remove are marked by [OfflineBusinessMethod] attribute, so if their callers don't use ObjectSet.DisableBusinessMethodCallRegistration, MethodCallDescriptors will be populated for them)

Everything will be properly rolled back in case if an exception will be thrown during client-side emulation of Transfer operation:

All ObjectSet modifications will be rolled back

Newly created MethodCallDescriptor will be invalidated and removed from list of MethodCallDescriptors in the ObjectSet


DoPetShop Remoting Client now utilizes offline layer (its original version was based on custom wrappers).
Note: its update isn't fully finished (e.g. security exception handling isn't implemented)

The following documents are updated: Benefits, ROI Calculation, Manual (and certainly, Revision History) - changes are mainly related to updates made in this version

Other minor updates


The following bugs were fixed:


Version 3.4

What's New

Microsoft SQL Server 2005 (Yukon) support - DataObjects.NET MSSQL Driver now supports Microsoft SQL Server 2005

Microsoft Access driver is added (in beta stage). See its description in .Chm/.HxS for details (MSAccess class); list of differences between this driver and SQL Server 2000 driver is available in the last part of Manual.

Mono support (in alpha stage) - most part of the DataObjects.NET is compatible with Mono now. Mono is open source, cross platform implementation of CLR (.NET Framework 1.1), see Adapter, Offline layer and BindingManager component weren't tested for compatibility yet.
Note: Trial Version doesn't include Mono-compatible version

[ShareDescendantTable] attribute

Transactional proxies for DataObjectCollection\ValueTypeCollection and their offline analogues are now generated


Lucene Full-text Search Driver: "UseRamDirectory" ConnectionUrl parameter is added

PropertyDescriptors are generated for non-persistent properties of offline types now

Extraneous joins are eliminated queries that using collection property in where clause

DataObjectCollection.CreateQuery: join is unnecessary when a collection is paired to a property of its owner type

Problem with using <Validator> and other similar attributes in VB.NET

Singnificant updates in caching layer (SessionCache, GlobalCache)

SessionCache.IsObjectCached(...):  result type is changed to StrongReferenceHolder

Session.IsReadWrite property migrated to Transaction.IsReadOnly property. This allows to e.g. discard read-write flag on the outermost transaction, if all nested transactions containing this flag were rolled back

GlobalCache performance counters support layer was updated

Other minor updates


"Transaction not closed" bug in the ObjectSetRequestProcessor

Possibility to get several objects in the same session with the same ID (SessionCache&GlobalCache bug), see

"If a DataObject descendant is tagged with the IHasNoAccessControlList and has a security parent different than the default one then getting or setting a property's value leads to StackOverflowException"

SecurityException in Session.BrowsePast mode

SerializationException if a permission's type is not found

Casting bug in LuceneFtIndexer

AccessControlList may throw InvalidOperationException

"Extend model dynamically - adding field to base abstract type"

"Domain.Build(): "Index was out of range" exception"

LoadOnDemandAttribute applied to ValueTypeCollection property

Other minor fixes


Version 3.3.3

What's New

Several performance counters are added, all of them currently reflects different GlobalCache usage statistics. See "DataObjects.NET Global Cache" performance counters category (Start - Control Panel - Administrative Tools - Performance)

Domain.ThreadedBuildExecution property controlling new mode of Domain.Build execution. When it's set to true, database schema extraction is executed in parallel with object & database models building, and later - proxy assembly generation is executed in parallel with database schema upgrade. In some cases this may speedup the build process by up to 40%. Many thanks to Mr. H. Veith for the idea and working implementation.

Manual GlobalCache\SessionCache invalidation methods are added (see e.g. SessionCache.Invalidate). They're useful if you modify the storage by e.g. an external tool that doesn't properly update VersionID column.

ApplicationName connection parameter is added for MSSQL driver (mssql://...), see


GlobalCache is now working while BrowsePast isn't active (earlier it was completely disabled when DomainDatabaseOptions.EnableVersionizing was turned on)

Approximately 100 constructors with different argument types were added for [Validator], [Corrector], [StorageValueModifier] and [TypeModifier] attributes. This should resolve their VB.NET compatibility problem, see


A set of internal problems in the GlobalCache\SessionCache were fixed. Their presence was not noticeable for end users or developers, but an efficiency of GlobalCache was seriously decreased because of them. Currently it seems it works completely correct - try e.g. running the same query with "with (LoadOnDemand)" option twice (in different transactions or Sessions - to check our global cache) + access all selected objects (or just run QueryResult.Preload()). Check out the performance of the second pass (on large amount of objects it can be more then twice as fast).

Replacing EveryoneRole with custom one (see Currently it's allowed to do this in the Domain.InitializeSystemObjects event.

RuntimeServicePool.RemoveRuntimeService is not available after Domain.Build (see

StackOverflowException in the Offline.DataObjectCollection code (see

Lucene index is optimized quite frequently (see Now IndexOptimizationPeriod connection parameter allows to control this behavior (see corresponding property in the LuceneFtsDriver)

It was impossible to use a Domain created with empty productKey parameter (ProductKey property was added earlier to allow specifying it later)

ÑacheableValue: cached value invalidation code is wrong (see

Use of DateTime.Now in RuntimeServicePool, CacheableValue and ClientSideCache code (see - now we either initially use DateTime.UtcNow, or ToUniversalTime() method in all places where date comparison occurs.

Problem with serializing offline objects (see

Internal "Security permissions changed" notification doesn't reach all necessary targets (see

[.NET 2.0 - specific] Getting FileLoadException after DataObjects.NET upgrade (see It's a result of problem in the .NET Framework 2.0, we implemented a workaround against it in DataObjects.NET for now.

Demo_Adapter: Person.FullName property should be [NotPersistent].


Version 3.3.2

What's New

IBindingList and ITypedList support for offline types is completely implemented

.NET Framework 2.0 build is shipped with Standard, Professional and Enterprise editions (binary + Visual Studio 2005 project and solution files)

ObjectSet.DataBindingOptions property is added - it provides access to ObjectSet-wide data binding configuration


!!! Important: DataObject.OnCreated method is added, and DataObject.OnCreate method is now invoked in the DisableSecurity() block. This means that all permission demands executed in OnCreate should be moved to OnCreated method. See

Internal refactoring of some parts of DataObjects.NET.Offline namespace (mainly to follow .NET coding standards better)

Trace switches are added to full-text layer (see DataObjects.NET.FullText namespace description)

BindingManager.BindingFlags property (static) is added - it allows switching to e.g. case-sensitive binding mode. See


AutoFixup.Block is not working properly (see

Runtime EnvDTE.dll dependency in Adapter: Adapter.GenerateMappings invocation leads invocation of one of internal methods containing DTE type reference (local variable of this type, that is actually never used on this invocation in the runtime) - this means that EnvDTE assembly is required for JIT-compilation of this method.

"DotLucene indexer is going crazy" (DotLucene index may constantly grow up, see

Persistent delegate properties can't be desterilized if version of assemblies they refer to are changed (see

"LuceneFtIndexer.Cleanup not cleaning up" (see

Offline.DataObjectCollection property content isn't loaded on demand

Compatibility problem with the latest build of .NET Framework 2.0 (shipped with Visual Studio 2005 beta2, see

Some exceptions thrown from Offline namespace contain incorrect text ("Session" word is used in it, rather then "ObjectSet", see


Version 3.3.1


DotLucene full-text indexing and search driver supports custom FtsCondition translation via LuceneFtsConditionTranslator type.

TrackingSet.Activity event is added.

More offline types implement ITypedList now (e.g. QueryResult). IBindingList support is also added to the most part of offline types, but it isn't completely finished yet.


Problem with loading DotLucene full-text indexing and search driver from resource (see

This version fixes several other problems found in v3.0-v3.3. Please see "Bug Reports" section in our Support Forum ( for details (all bugs marked as "Fixed in v3.3.1 or in post-v3.3" are fixed in this version).


Version 3.3

Finally we're ready to release a version of DataObjects.NET that supports:

Offline layer (disconnected ObjectSets)

DotLucene full-text search engine

Please see new DataObjects.NET PowerPoint Presentation - it contains lots of diagrams describing most important parts of DataObjects.NET, as well as briefly covers all new features.

What's new

Offline layer brings support for advanced DTO pattern into DataObjects.NET. Please refer to corresponding section of Manual or Presentation for additional information. Unfortunately development of this part has taken much more time then we expected initially - current size of C# code of Offline layer exceeds the size of first versions of core DataObjects.NET part (classes from DataObjects.NET namespace).

Full-text indexing and search abstraction layer is added. Now it's possible to add support for completely external full-text indexing and search systems into DataObjects.NET by implementing FtsDrivers for them. Please refer to DataObjects.NET.FullText namespace documentation for additional information.

DotLucene full-text indexing and search driver is bundled into DataObjects.NET. DotLucene is a port of Jakarta Lucene to .NET - it's free and very feature-rich full-text search engine. This driver is RDBMS-independent, so you can freely use it with any RDBMS, even if it doesn't support full-text search at all (e.g. MSDE or Firebird).

TrackingSet class is added. Each instance of this type tracks different types of activity of DataObject instances in the Session it was created in, such as instance creation, modification or deletion. Its usage allows UI tier to get the information about changes made by arbitrary BLL action (method execution) - to properly refresh controls displaying modified objects (or their properties). This allows to separate the UI tier from BLL much more then usual, since in this scenario UI shouldn't "know" what exactly should be refreshed after execution of any particular BLL action.

IQueryEventWatcher interface is added - its implementation makes shared DataService being notified on Query\SqlQuery-related events, such as query execution. This interface allows to transparently modify underlying IDbCommand - e.g. to apply an additional restriction to its "where" clause.

[Demand] attribute providing support for declarative security demands is added (see

DomainDatabaseOptions.UseOuterJoins option is added. This option significantly improves performance of all count(*)-like SQL queries. See for additional information.

DataObject.GetProperty\SetProperty fully supports "walk-through" mode now (see

SymmetricEncryptor is added (see


Documentation and Samples:

DataObjects.NET PowerPoint Presentation is available (finally we've made it J) - now it provides the fastest way to study almost all features of the product.

DataObjects.NET Manual and .HxS/.Chm Help are updated - they cover all new features.

New sample: Demo_DisconnectedSets. It shows how to use new Offline layer in 3-tier WindowsForms application.


Note: there are many modifications in all core types (such as DataObject, QueryBase, ObjectModel.Field) related to support of all new features (e.g. presence of new ToOffline(...) methods).


This release fixes most of problems found during last 3 months. Please see "Bug Reports" section in our Support Forum ( for details (all bugs marked as "Fixed in v3.0.2\v3.1b\3.2b\3.2c\v3.3b\v3.3c\v3.3" are fixed in this version).


Version 3.0.1

What's new

Faster domain startup - CodeDOM model isn't generated now, if cached proxy assembly can be used. See for additional information

TransactionInfo.User property is added. It allows to find out who committed a particular transaction in the versionizing mode

Domain.DatabaseOptions property is added. Domain.Versionizing, Domain.ForeignKeyCreationMode and corresponding configuration section attributes are available only as its parts (flags) now. New flag:

DomainDatabaseOptions.EnableFullTextSearch (the reason of adding it is described here:

Session.Mode property is renamed to Session.Options, consequently SessionMode enumeration is renamed to SessionOptions. Session.AutoDisconnect flag is available only as its part now. New flag:

SessionOptions.DisableInvalidObjectIdentifiers makes Session to throw an exception rather then returning null on attempt to get not existing object by its ID

DataObjects.NET.Offline namespace is added (with a set of classes). We left them here mainly to provide a brief documentation on upcoming disconnected operation mode. Currently there are no usable classes from this namespace - most of method bodies of these classes were replaced to throw NotImplementedException();

Classes from DataObjects.NET.ObjectModel were updated to support new types from DataObjects.NET.Offline namespace.


Microsoft SQL Server driver bug: build fails if non-DataObjects.NET tables are added to its full-text catalogue:

Oracle driver bug: only uppercase user names are acceptable:

Oracle driver bug: dropping an index works only if whole its table is also dropped:

Oracle driver bug: QueryBase throws an exception on queries with subqueries (where ... in {Select ...}) while working with Oracle driver

TransactionController tc = new TransactionController(...) was replaced to TransactionController tc = session.CreateTransactionController(...) everywhere uncluding ProxyBuilder-generated code. The problem is mentioned here:

DataObject.Item, DataObject.GetProperty, DataObject.SetProperty now ignores the culture parameter for not [Translatable] properties (rather then throwing an exception, if it's specified\not equal to null).


Version 3.0

We wish Happy New Year to all our customers and clients! We really appreciate your attention to our products and services!

What's new

This time this part is rather short - it contains mainly a list of new features. Almost all of them are described in new version of DataObjects.NET Manual.

New DataObjects.NET Manual finally became available. We tried to make it much better, then previously.

Firebird database driver is added.

Versionizing mode is added - it provides an ability to "see" the database at any previous state (point in time). This mode works only if it's turned on for the whole Domain.

Domain.GlobalCacheSize and Domain.GlobalCache are added. So now DataObjects.NET utilizes global (Domain-level) caching in addition to Session-level caching.

Domain.ObjectModelBuilt is added. Allows to modify the ObjectModel at runtime (during Domain.Build(...) execution)

Session events: there are no regular event delegates in Session, but you can use DataServices to implement event handling. You'd just implement one of following interfaces in some of your DataService types to get notified on necessary category of events:

IDataObjectEventWatcher should be implemented by shared (see DataServiceType.Shared) DataService, if it needs to be notified on DataObject-related events, such as creation, modification and deletion

ITransactionEventWatcher should be implemented by shared (see DataServiceType.Shared) DataService, if it needs to be notified on Transaction-related events, such as transaction beginning and committing

Now database identifiers are automatically hashed at tails, if their size doesn't meets identifier size limitation of underlying database driver.

ServiceTypeAttribute.ServiceVisibilityLevel property is added.

New samples:

Demo_Versionizing demonstrates new versionizing mode

Demo_ExtendedObjectModel utilizes Domain.ObjectModelBuilt event to extend ObjectModel at runtime

Other minor changes


All bugs fixed in v3.0 are listed here


Version 2.6

We strongly recommend anyone to upgrade to this version - besides a set of important improvements and new features it brings a set of very important performance-related bugfixes.

What's new

DataObjects.NET.UI.BindingManager - a tool for binding DataObject\regular properties to ASP.NET\WindowsForms controls. Its features:

Implemented as .NET component built-in into DataObjects.NET.dll - you can add it to your Visual Studio .NET toolbox

Binds properties-to-controls, but not properties-to-properties (regular databinding)

Highly configurable (provides a set of interfaces allowing to extend it)

Utilizes VisualStudio.NET IExtenderProvider interface to add its own properties (BindingExpression, BindingProperties); supports extraction of these properties from additional attributes (with the same names) applied to ASP.NET Control tags

Supports custom binding extenders (see IBindingExtender interface), as well as controls that explicitly supports it (via IBindableControl interface)

Supports automatic version checks (optimistic updates) via VersionCodeValidator extender.

Completely external to DataObjects.NET, i.e. it doesn't use any internal members of DataObjects.NET to access the data. Thus its use can't lead to violation of business rules, security restrictions, etc.

See Demo_BindingManager_Web and Demo_BindingManager_Win samples.

Delegate properties are fully supported. Single column is used to store the value of such property (thus it's stored in the serialized form).

Clustered indexes. Now DataObjects.NET builds a clustered index on any primary key by default. You can customize this behavior by applying [Index\Indexed(..., Clustered = true)] attributes.

Full-text indexing layer was seriously improved:

FtIndexer never changes object VersionID value now

FtObject.FtRecord property was removed (this one-to-one relationship is now defined only by FtRecord.FtObject property)

Now you shouldn't do anything additional to implement IFtObject, except adding a single indexed property (FtRecordIsUpToDate) and providing ProduceFtData implementation. Everything else is supported by DataObject code. See FtObject code for details - it's very short now.

[ChangesTracking] attribute can be applied to properties of any type (earlier it was possible to apply it to collection properties only). If it specifies to track changes independently for a regular property, the change of this property won't affect on VersionID. Useful, when it's necessary to implement such properties as FtObject.FtRecordIsUpToDate - this property is checked by FtIndexer query only, and certainly it's desirable to keep VersionID unchanged while FtIndexer updates this property (in this case full-text indexing won't affect on VersionID at all).

Threshold property is added to [LoadOnDemand] attribute - it allows to load relatively small [LoadOnDemand] properties without additional queries needed to fetch a value of such property. Exactly it specifies how large the property value should be while it's possible to keep its copy in FastLoadData column (if it's larger then Threshold, nothing is kept).

New behavior is fully supported by collection properties - you can specify that a collection may reside in FastLoadData also, while it's relatively small (say, less then 16 elements)

[LoadOnDemand] with Threshold can be used only for [ChangesTracking(ChangesTrackingMode.ThroughOwner)] properties (properties, these changes are tracked by owner's VersionID value). This is obviously necessary, since any change of such property affects on FastLoadData value, and consequently - on VersionID value.

Subqueries are now supported in Query - use {Select ...} syntax for them.

An example:
  Select top 100 IFtObject instances as $fto with (SkipLocked)
  where not exists {Select FtRecord objects where {FtObject}={$fto} }


"}}"  and "{{" (double figure brackets) are subject to substitution everywhere except in string constants - they're always translated to single ones (such as \" in C# strings). Use empty spaces to set them up correctly (e.g. space is used in the tail of example query: "} }")

Use as $alias to alias subqueries

We recommend you to always profile queries containing subqueries (e.g. see the execution that SQL Server generates for them)  - they can be very inefficient (e.g. lead to table scans, and consequently - to table-level locks) - in such cases it's better to replace them with distinct\join queries, if possible.

Less-important changes:

Changes in Domain type:

Environment property is added, as well as IEnvironment interface. Allows persistent types and services to interact with environment (i.e. web application), in which they run, or it's better to say, provides a common way of doing this.

TransactionalUpdate property is added. Specifies, if all Domain.UpdateActions should be performed in a single transaction during Build execution; otherwise each action will be executed in its own transaction (this may be much faster, but less safe). Default value is true.

GetRegisteredPermissions method is added. Currently it returns a list of all available security permissions via reflection.

Changes in Session type:

Default value of ReprocessingAttemptsCount is set to 10, of ReprocessingDelay - to 200.

Changes in DataObject type:

VersionCode property is added (not persistent), as well as CompareVersionCode method. VersionCode is a string identifying "UI version" of instance.

Usually lots of types can be modified by user (manually) and by some automatic services, such as FtIndexer. Since both update types change VersionID property (actually FtIndexer doesn't change its value starting from v2.5, but this can be done by your own similar services), it's impossible to use its value for detecting the "UI changes" (changes made to the same object by different persons - e.g. to implement an optimistic locking behavior in the web application (i.e. to show the "Object is modified by someone else" message, rather then simply update the object).

VersionCode property provides a common way of doing this - by default any DataObject instance returns its VersionID value from this property, but you can override this behavior in your own persistent types. E.g. you can return a value of ModifyDate property (custom one), that isn't changed by any service-made updates, and thus allows to detect the UI-made updates better (i.e. to separate both types of updates).

GetIDs method (protected) is added; it's very similar to GetProperty, but gets a list of IDs stored in some persistent property, rather then property value itself. Works for root properties only, currently - of DataObject\DataObjectCollection\ValueTypeCollection\struct type. Very useful in different preload scenarios. See DoPetShop.Model.Product.ProduceFtData method as example of its usage.

InvalidateFtData method (protected virtual) is added. Invalidates full-text record associated with the current instance by setting its IFtObject.FtRecordIsUpToDate property value to false - to make FtIndexer to update associated FtRecord object further. Normally you shouldn't invoke this method manually or override it - it's automatically invoked in OnPropertyChanged, OnPropertyContentChanged and similar methods.

Changes in ValueTypeCollection type:

New version of Add method is added - it returns a ValueTypeCollectionEntry object containing newly added item.

Contains and IndexOf methods now capable of searching the item not only by loading the whole collection, but by running a query selecting it. Search method is selected automatically (currently in-memory search is used only if collection is completely loaded, and contains less then 64 items); query-based search uses shortest unique index, and works only if such index exists.

ValueTypeCollectionEntry class is updated - see its CreateUnbound method (static) and IsUnbound property.

Several other performance-related improvements

Some of Trial Version limitations were removed\modified (by user requests):

Number of persistent types (DataObject descendants) supported by Trail Version is increased to 50, number of tables generated for them - to 100, and number of DataService types - to 16

Instance ID restriction (less then 100000, otherwise DataObjects.NET starts to significantly slow-down the application) is removed from Trial Version. So now it's possible to try our product on databases of any size.


DoPetShop Content Generator - allows to generate as many Products \ Items in DoPetShop, as necessary. It connects to DoPetShop application via .NET Remoting, and utilizes 2 newly added services. Notes:

We didn't optimize DoPetShop for large databases by any way (e.g. it doesn't use such classes as QueryPager to display large collections, etc.). Nevertheless it works very well on 1000000-object database (check out search for example).

The speed of content generation may be lower nearly by 3 times then the speed of regular instance creation - the main reasons of this include remote interaction (HTTP channel is used) and full-text indexing (Content Generator executes FtIndexer explicitly - to decrease the concurrency with FtIndexer instance running in DoPetShop domain as runtime service)

For these who interested, main (UI) and worker thread interaction\synchronization is used in this sample: worker thread safely updates WindowsForms controls in the main thread; graceful\emergency shutdown of a worker thread is implemented.

Demo_BindingManager_Web and Demo_BindingManager_Win using new BindingManager component

Demo_Adapter is updated (it utilizes optimistic update mode and provides Window menu)

Demo_Collections - very similar to Demo_Transfers: shows highly concurrent operations on collections and built-in deadlock reprocessing capabilities


.HxS\.Chm help is compiled with NDoc 1.3 beta2 - new NDoc generates much more comprehensive documentation (direct descendants \ implementers are always shown on summary pages, implemented interfaces - on namespace hierarchy pages, etc.)

Available Source Code Package is updated


"Automatic transaction re-processing bug"

"Session.Preload() bug"

"Query performance problem"

"[Nullable] string property problem"

"A problem with pairing to an interface property"

"Problem with Adapter class mapping procedure"

"DomainConstructionException error on domain update"

Impossibility to use spaces to separate indexed properties in IndexAttribute(string, string) constructor (so e.g. "A,B" were acceptable, but "A, B" - not)


Version 2.5

What's new

DataObjects.NET.Data.Adapter - universal tool for exporting DataObject instances into DataSets and importing them back. Its features:

Implemented as .NET component built-in into DataObjects.NET.dll - you can add it to your Visual Studio .NET toolbox

Extremely highly configurable

Utilizes VisualStudio.NET code model to provide lists of available persistent classes and properties at design time

Automatically generates mappings at design time (right-click on component to access common mapping actions), as well as in runtime, if DataSet objects (tables and columns) are named as types and properties of persistent objects. Runtime mapping schema generation allows to almost forget about necessity to design it!

Fully transactional - ensures that even DataSet won't be changed in case if rollback occurs

Supports "fill after update" - i.e. allows to import values of dependent\volatile properties (such as VersionID) back after Update

Completely external to DataObjects.NET, i.e. it doesn't use any internal members of DataObjects.NET to access the data. Thus its use can't lead to violation of business rules, security restrictions, etc.

There are wide set of applications for this tool - it allows to easily bind DataObject instances to WindowsForms controls, provides one more standard way of data exchange between different applications (DataSets are almost ubiquitous), can simplify development of legacy data conversion tool and more. Demo_Adapter shows it in action.

Paired ValueTypeCollections brings explicit support of paired n-ary relationships. For example, such relationship as SecureObject - Principal - Permission (with additional attributes, such as IsGranted\IsDenied) now doesn't require additional persistent type, and moreover, it's easy to make it work in DataObjects.NET "two tails" access fashion (with use of multiple PairTo attributes). See [ItemType] and [PairTo] attribute descriptions for examples.

Explicit support of one-to-one relations - [PairTo] attribute now allows to establish paired relation between two reference fields. Note that this behavior is implemented a bit differently in comparison to usual [PairTo] behavior - both fields ("master" and "paired") utilizes their own columns, but always kept synchronized. In this case such approach looks better from the point of performance.

Optimized instance removal process - now DataObjects.NET removes instances not one-by-one, but always tries to remove a group of instances at once. This doesn't mean it sends batches of "delete from ..." commands to SQL Server - this could surely improve the performance, but not as good as we can. The most time-consuming operation here is robust reference location process - you know, DataObjects.NET locates and destroys all references to any removing object before it actually removes it. To find these references, DataObjects.NET runs optimal amount of queries, but earlier these queries were executed per each instance removal. So if you want to remove one object that contains (see [Contained] attribute) e.g. 1000 other objects of the same type, and there are 10 independent (newly declared) persistent properties that can hold a reference to this type, DataObjects.NET should perform nearly 10000 queries (1000*10, 10 queries per each removal operation) to locate these objects. DataObjects.NET dramatically changes this behavior - most likely it will perform nearly 1100 queries to remove everything.

DataObjects.NET utilizes DataObjectRemovalQueue to optimize the whole removal operation (i.e. locate all contained objects, destroy references to them at once and remove a whole group of objects). See DataObject.RemovalQueue property (it available during any removal operation)

Session.RemoveObjects(...) method allows to explicitly remove a group of objects at once

Now you can preload everything in a single bulk preload operation - instances, [LoadOnDemandFields], DataObjectCollections and ValueTypeCollections!

Session.Preload(idList\QueryResult\ICollection, string[] fieldnames, Cultur[] cultures) preloads a set of DataObject instances, their [LoadOnDemandFields] fields and collections by executing optimal amount of queries

Moreover, it performs internal cache checks before putting an object or collection to its bulk preload list! So you shouldn't care about preparing preload lists - everything that is already loaded will be simply skipped, decreasing not only the amount of fetched information, but even the amount of queries.

Any Preload-like method now returns StrongRefrenceHolder object allowing to keep preloaded data as long as its necessary

Less serious improvements:

AccessControlList.GetFlatPermissions(), GetEffectivePermissionSet methods are added, both significantly helps to produce GUI representation of object's permission inheritance hierarchy.

DataObject.OnSerializeIdentity() \ OnDeserializeIdentity() methods allow to use custom object identities during serialization\deserialization. See DataObjects.NET.Security.Principal \ DoPetShop.Model.Category classes' code for examples.

Session.CommandTimeout property is added, as well as corresponding session security option

Domain.RemoteSessionSecurityOptions property is added (similar to Domain. SessionSecurityOptions, but controls remotely created sessions).

ObjectField now supports [SqlType] and [Length] attributes

proxyAssemblyOutputFolder and identifierPrefix options are supported in Domain configuration section (see Configuration class).


Any exception thrown by validators is wrapped into ValidationException now. ValidationException falls through automatic transactional handler of DataObject.SetProperty method without rollback

LengthValidator now associated with any string \ byte[] \ object fields except these resides SqlType.AnsiText \ SqlType.Text \ SqlType.Image columns

Truncator now has optional TrimStart\TrimEnd parameters

MatchesRegex validator is added (original code was contributed by Mr. Horst Veith)


DataObjects.NET.RuntimeServices namespace is removed. Furher we're planning to use DataObjects.NET. Services and DataObjects.NET.Services.Runtime namespaces.

FtIndexer is moved into  DataObjects.NET.FullText namespace

IDataObjectField is renamed to IDataObjectFieldValue

IRemovableField is renamed to IRemovableFieldValue

IRecyclableField is renamed to IRecyclableFieldValue

IDataObjectExternalFieldValue is added.


"DataObjectCollection.Contains may fail in the Offline mode"

"Can't use [SqlType(SqlType.VarBinary)]"

"DataObjects.NET fails on product key validation (Domain constructor throws DataObjectsDotNetException ("Invalid product key.")) in the following case:
1) Current thread is impresonated to UserX
2) Profile of UserX isn't loaded"

"PagerEnumerator throws an exception when query returns empty result set"

DataObject.SecurityParentChanged() method bug (introduced in v2.3.5)

Domain update in DomainUpdateMode.Block always blocked, if Domain.ForeignKeyCreationMode is DomainForeignKeyCreationMode.Default.

Two bugs in DoPetShop


Version 2.3.5

What's new

Native Oracle Driver is now embedded into DataObjects.NET as resource. So it's necessary to ship just one assembly with any DataObjects.NET-based application.
Note for Professional\Enterprise Edition users:

DataObjects.NET.dll with embedded Native Oracle driver is placed into Source\Drivers\All Embedded\Output folder. Source\bin folder contains regular DataObjects.NET assembly (this assembly will try to load Native Oracle Driver by an old way also).

Native Oracle Driver Debug symbols (DataObjects.NET Native Oracle Driver.pdb) are also embedded into Debug version of DataObjects.NET.dll as additional resource; DataObjects.NET is capable of loading this resource with debug version of Native Oracle driver, so it's possible to step into Native Oracle driver while debugging DataObjects.NET.


IDbCommand.CommandTimeout is now set to 0 for any command running while database schema update is performed (quite necessary in DomainUpdateMode.PerformComplete)

QueryPager bugs are fixed, see for details.


Version 2.3.4


We've fixed a problem in NDoc - it builds namespace hierarchies that may contain classes that neither declared in the specified namespace, nor ancestors of classes declared in the specified namespace (so they shouldn't appear in the namespace hierarchy). We use NDoc to build DataObjects.NET documentation, and generally NDoc is excellent. But this problem exists in it for at least one year, so finally we decided to fix it ourselves. Consequently, DataObjects.NET documentation now contains "clean" namespace hierarchies.
Solution is already sent to You can download a patch (updated XSLT files) for NDoc 1.3 beta1a here:

Links to Support Forum Archive in .HxS\.Chm Help now points to its offline version, when it's possible.


 "Exception on reading LoadOnDemand fields" bug.
See for details.

 "I'm frequently getting "Find Source" dialog" bug.
See for details.


Version 2.3.3

What's new

Support Forum Archive (offline version of DataObjects.NET Support Forum) is integrated into .HxS\.Chm Help. We'll update it on each successive release, or at least once per month.

DomainUpdateMode.PerformComplete is added. DataObjects.NET additionally checks row-level database integrity in this mode.

DataObject, AccessControlList classes are seriously optimized internally. The effect of this optimization is that now much less amount of memory needed for a single DataObject instance (nearly by 2-3 times less then previously). The result:

Instance cache should work nearly 2 times more efficiently

Creation of a single instance (for example, on fetch) takes less amount of time - now it's 2 times faster then before (approximately, for instance having ~ 10 persistent properties).

All property access tasks are also executed faster, since L2 cache works nearly 2 times efficiently

DataObjects.NET.ObjectModel.Activator class is added. This class has only abstract methods allowing to create DataObject\DataService\DataObjectCollection\ValueTypeCollection instances of a particular type. ProxyBuilder generates its descendant having any method of its base class implemented, and DataObjects.NET utilizes it to create an instance of any necessary type (or it's better to say an instance of proxy type for any necessary type) in the runtime. Earlier proxy instances were created with use of reflection (that was the only task requiring use of reflection in the runtime). Now it's handled much faster (at least 10 times or more).

All database drivers are optimized for better performance:

Number of intermediate objects needed for frequently used operations is significantly reduced.

Updated drivers are capable to interact with Session's cache - no DataObject instantiation data is transferred to Query\SqlQuery objects, if driver discovers that object it's trying to fetch is already cached in Session and its version is correct (only object IDs are transferred in this case).

QueryOption.LoadOnDemand now handled differently - it makes database driver to fetch both ID and VersionID columns (rather then just ID before). VersionID is used only on database driver level - to transparently mark all cached instances having correct IDs and VersionIDs as valid. This prevents further attempts to perform a version check for such instances, thus increasing the performance.

IHasNoAccessControlList interface is added. This tagging interface allows to block use of AccessControlList for a particular type (so a Permissions property of any its instance always returns null). This doesn't mean that instances of this type are completely insecure - this just means that they forward all security checks to SecurityParent (so it's similar to consider that such instances always inherits a complete ACL from SecurityParent). Note that other objects are allowed to return IHasNoAccessControlList object from SecurityParent property. Why this having no AccessControlList is useful? First of all, there are some objects that shouldn't have their own ACL naturally. And second, an object having no ACL requires less memory, thus improving use of L2 cache, and consequently - performance.

New Pager and QueryPager classes allowing to browse large collections page-by-page are added. Please refer to their descriptions in .HxS\.Chm Help.


"Some objects may become invisible after injecting an intermediate type into existing inheritance hierarchy" bug. Now DataObjects.NET always performs row-level integrity check for any newly created table. See for details.

Primary key violation occurs on creating an instance of descendant of a class that doesn't declares any new field (usually - abstract), and [ShareAncestorTable] attribute is applied on this descendant. See for details.

"Foreign key violation occurs on creating an instance of descendant of a class that doesn't declares any new field (usually - abstract)" bug. See for details.

"Pairing to an interface property" bug. See for details.

Additional Notes

We recommend you to backup your existing database before switching to this version - it doesn't understand FastLoadData formats introduced in v2.0 (it supports only v2.3 FastLoadData formats).

We recommend you to backup your existing database before using PerformComplete update mode - nevertheless we strongly recommend updating your database in this mode.


Version 2.3

What's new

New Session.Mode property is introduced. It allows switching the Session to offline operation mode (see SessionMode enumeration).

DataObject instances don't reflect actual state of underlying database entities in this mode (in contrast to online mode), except they always displays the state when they were originally fetched.

Automatic transactions aren't created for any transactional method - some of them (that supports offline mode) may execute without creating a transactions. E.g. almost any data read methods don't run transactionally, if the data they should return is available in cache.

Any data modification operations require transactions. All update operations work in optimistic locking mode (throws exception if object version conflict occurs).

Complete foreign key generation is implemented (foreign keys are created even for not [Nullable] reference properties). See Domain.ForeignKeyCreationMode property for details.

New attributes:

[Validator] - attaches one or more validators to persistent property. See DataObjects.NET.Helpers namespace for list of all available validators and correctors. Custom validators and correctors are supported.

[Corrector] - attaches corrector to persistent property

[StorageValueModifier] - attaches storage value modifier to persistent property, e.g. Compressor (transparently deflates\inflates byte[]\object property storage values using Zip compression). Custom storage value modifiers are supported.

[TypeModifier] - allows to associate a different internal type (in comparison with actual property type) with some persistent property. For example, it allows to expose some property as object, but internally store it as string.

[ShareAncestorTable] - applied on class level, allows to share a single table between properties declared in several different classes.

[AutoFixup]- allows to disable automatic reference property fixup (setting it to null) on removal of its target. By default fixup is automatically performed for all reference\collection properties as part of robust instance removal process, but it may be useful to not using it for a particular property. Note that foreign keys aren't generated for such properties (their values may lay out of primary key set).

Caching-related features:

CacheableValue, CacheableCollection, CacheableQueryResult - useful helpers for persistent data caching. These objects "wraps" a value that can be cached, and ensures validity of cached value on any attempt to read it. Cache validity checks are based on TransactionContext in which cached value was calculated, CalculationTime and ExpirationPeriod. Example:


   session.Mode = SessionMode.Offline;

   CacheableQueryResult qr = new CacheableQueryResult(

       session.CreateQuery("Select Country instances with (Count)"),

       new TimeSpan(1000));

   Console.WriteLine("Number of countries: {0}", qr.Count);


   Console.WriteLine("Number of countries: {0}", qr.Count);


A new virtual method is added to DataObject class: OnBeforeReload(ref bool skipReload).    You can override this method to disable instance reloading under certain circumstances (e.g. when it's well known that instance almost never changes, an example of such object is SecurityRoot object).

ExeName.config\Web.config - based Domain configuration is now supported. See Configuration class and Web.config of DoPetShop for details.

Delayed creation of nested transactions and savepoints: DataObjects.NET now delays creation of any savepoint or nested transaction till the moment of first write operation, thus sometimes it doesn't create it at all (e.g. in case with read-only nested transactions). This should significantly speedup tasks utilizing a lot of inner transactions but primarily reading the database.

[Nullable] 1  not [Nullable] conversion is now fully supported by database schema upgrade layer. Domain.Build(DomainUpdateMode.Perform) handles this type of conversion for any property type (reference properties are handled in a special way - e.g. NULL values can be replaced to 0 values and vice versa).


Error in DataObjectCollection implementation, see this topic for details:

Error in BlobField\StringField exception throwing code, see this topic for details:

[Index] attribute can't be used in VB.NET,  see this topic for details:

ProxyBuilder incorrectly reproduces attribute declaration containing Enum property, see this topic for details:

Error in Query class leading to impossibility to run "Select (SomeType)Class.ReferenceField instances" queries.


Version 2.2.9

What's new

All Index Service Filters are available via Filter type. Now it's possible to index almost any document\file type stored on the database server (or externally). In particular you can index the following document types: Microsoft Office files (.doc, .dot, .rtf, .xls, .ppt, etc...), HTML files (.htm, .html), plain text files (.txt, including unicode files).

You can install additional third-party filters to index other file types, e.g. Adobe PDF IFilter:

Filters are available even while Microsoft Index Service isn't running.

See new Demo_FullTextFilters for quick start.

Foreign keys support. Now DataObjects.NET is capable to automatically create\update foreign key constraints (currently only Microsoft SQL Server driver supports this feature).

Domain.ForeignKeyCreationMode property allows to specify if it's necessary to create\update foreign keys during Domain.Build() execution.

Currently foreign keys are created for DataObjectCollections, ValueTypeCollections, [Nullable] reference fields and TypeID column.

We recommend to use DomainForeignKeyCreationMode.CreateForeignKeys only when it's really necessary - DataObjects.NET enforces referential integrity anyway, with or without them, but use of foreign keys makes SQL Server to additionally check these constraints (so this may lead to small performance impact).

One interesting fact: we've made just a single 1-line change to our persistence layer to make this feature working (except extending the database schema upgrade layer): currently DataObjects.NET flushes all delayed updates before executing SQL sequence that actually removes a DataObject instance, if foreign keys are used. Otherwise a foreign key constraint may be violated - DataObjects.NET "resets" all references to removing instance prior to actual deletion, but these updates may be delayed. Of course flushing of delayed updates prior to removal isn't necessary, if there are no foreign keys, since this action will anyway occur further, or a whole transaction will be rolled back. The conclusion: our reference tracking mechanism works perfectly!

Note: It will be impossible to start DoPetShop in (DomainUpdateMode.Perform,  DomainForeignKeyCreationMode.CreateForeignKeys) mode first time after upgrading to this version, since its previous version contains not-[Nullable] reference properties while current - not (all reference properties are marked by [Nullable] attribute in it), and thus there are some "referece" columns containing 0 values (except null) - DataObjects.NET will fail on attempt to apply constraints on tables containing such columns. Use DomainUpdateMode.Recreate to upgrade it.

RemotingEndPoint class was added - it eliminates the need to "ping" a remote application hosted in IIS by HTTP request before accessing its Domain object (to ensure that application is running now), plus simplifies remoting configuration (e.g. now this can be done completely on application configuration file level). See DoPetShop and DoPetShop Remoting Client as example.


Domain.DefaultUpdateMode property is added, see its description for details (may be useful, if the Domain is configured by an external tool prior to execution of its Build method).

DataObjects.NET assembly is now marked by [ClsCompliant] attribute (this means it's really CLS-compliant).


A problem with attaching event handlers to Domain events in VB.NET. Due to a bug in VB.NET compiler it was impossible to attach a handler to Domain.Initialize \ Domain.InitializeSystemObjects events (bug description is available here:;en-us;814605).

An error in ConnectionInfo class leading to the following problem: parameters part of connection URL (everything after "?" sign) was completely ignored. This problem appeared in one of 2.2.X releases.

ProxyBuilder was incapable to add references to assemblies containing not persistent interfaces that were implemented by some persistent type. It was possible to walk around this bug by applying additional [TypeReference] attribute.

When adding the [Nullable] attribute to a property, a Domain.Build(DomainBuildMode.Perform) does not change the table to allow the column to be nullable.

A serious problem in OracleExtractor: OracleExtractor always reports there are no autoincrement sequences in the database, thus it was impossible to use Domain.Build(DomainBuildMode.Perform) with Oracle. This problem has appeared in v2.2.5 (all database drivers were seriously updated in this version).

SAPDBUpdateActionTranslator produces incorrect definition for CHAR ASCII columns.

Any exception thrown in DataObject.OnCreate methods is wrapped into TargetInvocationException while falling into the client code.

A set of new explicit checks were added (such as attempt to use already disposed Session instance, etc.).


Version 2.2.5


Database schema update layer now takes into account default values of Enum types (first elements in enumeration lists). Formerly DataObjects.NET was creating columns with default value 0 or '' (empty string) for any Enum property, that's generally not quite correct, since some Enum types doesn't contain 0 in the list of allowed values.

Optimized proxy assembly compilation and loading. Currently DataObjects.NET doesn't rebuild proxy assembly if Domain.ProxyAssemblyOutputFolder is set to non-empty string, and previously compiled assembly is up-to-date. See for details.

All Holder properties (e.g. IDataObjectField.Holder) were renamed to Owner.

Interface IDataObjectFieldHolder was removed (it was publicly implemented in the DataObject type only).

Query\SqlQuery improvements:

No more compromising QueryResultTypes: only QueryResultType.Instances and QueryResultType.Values.

ValueTypeQueryResult now iterates through ValueTypeQueryResultEntry objects rather then ValueTypeCollectionEntry objects. This brings a set of additional benefits - e.g. it's possible to access IDs of selected objects and ItemIDs of collection entries without referencing (and consequently loading) selected them. Nevertheless ValueTypeCollectionEntry provides Value property allowing to access selected objects by almost the same manner.

Now it's possible to join a type not only "by reference" (see FIELDJOINEXPRESSION term in the Query language description), but by any other condition: "Join ... as $alias on (...)". The same construction is available for joins "by reference" also.

Type casts now allowed for any DataObjectCollection\reference property (i.e. properties contained in structs or ValueTypeCollections can be casted to descendant types).

Two types of queries are supported:

Instance fetching queries: specify a type or reference\DataObjectCollection field in Select list to execute a query fetching DataObject instances. Reference fields contained in struct fields or ValueTypeCollections are fully supported.

Value fetching queries: this type of query can be executed against any field - it allows to safely browse selected values of this field ( "contained" fields are fully supported).

Auto-aliases: $root, $rootOwner, $rootItem, $rootItemOwner. $root is always available, other aliases available dependently on context (underlying select declaration).

Field-culture declaration was changed:

Now you can't use ':' to specify a culture of the field in query (only '-' is allowed - we're making our query specification more strict);

Culture should be specified after root fields only. Root fields are fields exposed by DataObject descendants. Formerly it was necessary to specify the culture in the end of field reference declaration. New specification reflects DataObjects.NET behavior better.

See Query Tutorial in DataObjects.NET Manual for examples and comprehensive description of new query syntax.

Query compilation exceptions become slightly more informative.

We decided to remove SqlJoinType.RightOuter and SqlJoinType.Cross (these types weren't completely supported formerly).

"Articles" sample was slightly updated (primarily to work correctly with updated Query).


Query.ExecuteCount returns last instance ID rather the number of instances (this problem appeared in v2.2). See for details.

A list of TypeID isn't synchronized with the database in DomainUpdateMode.Skip and DomainUpdateMode.SkipButExtract. See for details.

[DbName] attribute applied to properties isn't inherited. This leads to incorrect view column names (they are named as if there is no [DbName] attribute) in views related to descendants of type where such property was declared. This makes impossible to execute a query against descendants containing a reference to such property - an error occurs, since Query parser puts correct [DbName]-based name of the property into the underlying SQL query.

QueryOptions.Distinct doesn't work correctly with QueryResultType.Values (formerly - CollectionValues).

Guid and TimeSpan types now are natively supported. Guids become inavailable in v2.2 - this version was the first release aware of internal structure of any struct field. Guid and TimeSpan are structs, so starting from v2.2 DataObjects.NET persisted these fields by storing their internal fields in several database columns (one per each field). Now all works fine:

You can use SqlType attribute with Guid fields (SqlType.Guid and strings are allowed, SqlType.Guid currently available for Microsoft SQL Server only, Oracle\SAP DB\MaxDB drivers use SqlType.AnsiChar in this case).

TimeSpan is always persisted to SqlType.Int64 columns.

Fields of both types can be indexed, used in structs, ValueTypeCollections and queries - absolutely in the same fashion as any other persistent property.

Query "Select SomeType objects where" passes without an error (empty where clause is allowed).

InvalidConnectionURLException was renamed to InvalidConnectionUrlException.

Exception handling code in ConnectionInfo was fixed: it was catching some important exceptions (e.g. thrown on database driver load failure) and substituting them to InvalidConnectionURLException.


Version 2.2.1


DataObjects.NET FAQ is updated.


DataObjects.NET.dll version number is fixed (now it's;

A problem with abstract protected DataObjectCollection \ ValueTypeCollection members is fixed: ObjectModelBuilder considered such properties as abstract members, thus it didn't generate a proxy for a whole class containing such member.


Version 2.2

Most of new features in this version were implemented to allow developers to optimize the performance of DataObjects.NET-based applications. Brief list of the most important features:

Support of ValueTypes (struct fields);

Collections of ValueTypes (ValueTypeCollections);

Significant Query improvements: joins, type casts, collection-based queries, support of ValueTypes and ValueTypeCollections;

DataObjectCollection now supports partial loading of its contents (as well as ValueTypeCollection);

New attributes:

[Alias] (allows to specify synonyms for your type and class names);

[DbName] (allows to override auto-generated names of tables, views and columns);

[ChangesTracking] (determines ChangesTrackingMode for collections, allows to decrease the level of concurrency).

Access control system improvements:

AccessControlList.Inherit property;

New ACL inheritance mode (see DomainSecurityMode enumeration);

New password hashing methods preventing detection of equal passwords by hash comparison.

Sample updates:

DoPetShop now supports editing of its catalogue. Login as "Administrator" and use "Admin" button to enter the management subpart.

A new sample was added: Demo_Articles, it shows new features of Query and utilizes ValueTypes and ValueTypeCollections.


Note: This version includes very serious low-level changes, please create backup of your existing databases before migrating to it.


Note: Most likely you'll have to perform very minor changes to the existing code while migrating to this version. There is only one most probable change required, it's mentioned in the "Access control system improvements" section.

What's new

ValueTypes (struct fields)

Now you can use any struct type in persistent property of DataObject. Such properties aren't stored in the binary serialized form (as properties of unknown serializable types), but exploded into sets of columns. Internally DataObjects.NET handles such properties as "combined" (described by StructField) properties consisting of other primitive (described by PrimitiveField descendants) or combined (described by StructField) properties.


It isn't necessary to register struct types you're going to use - such types can be stored only in DataObjects, so DataObjects.NET is capable to find all such types by studying registered persistent types (DataObject descendants).


You can use persistent collections of struct types (ValueTypeCollection properties or properties of custom descendants of this type).


Why do we think these features are important?


It's inefficient to use DataObject instances to store small amounts of information, since any DataObject contains significant amount of system-managed information (nevertheless this information is necessary - without it it's simply impossible to achieve other important goals). Let's imagine we should store a set of lists (may be rather big lists) of RGB values or vectors (X,Y,Z coordinates). It's inefficient to use a DataObject instance to store each element of such list... This seems strange, since regular databases are capable to handle such tasks efficiently enough, and DataObjects.NET works over them.


Now it seems this problem is solved - ValueTypeCollection fields are designed to handle such tasks with nearly the performance of regular database tables.


DataObject instances may act as containers where smaller objects (structs) can reside, and you may choose between these two approaches of storing different types of entities in your application.


But what do you loose with structs? You loose all inherence-related features (structs can't be inherited even in .NET, you won't be able to select different types of structs in a single query, query them by a supported interface, etc...) and some BLL features. For example, struct can't react on its modification itself, but DataObject instance that stores it - can. You can't apply security restrictions on a particular struct, but you can apply them on DataObject that stores it. You can't locate a particular struct by some universal ID, etc...


But of course you'll gain the performance and space in the database in exchange.


Now let's look ok some interesting features of our implementation:

DataObjects.NET has built-in access control system. So we can't allow anything that may act as "backdoor" in it. And you still can't override security restrictions by e.g. executing a query fetching ValueTypeCollection items - new Query allows to execute such queries, but any access to elements of ValueTypeQueryResult is conducted through DataObject instances that hold selected items (so you'll anyway receive a set of DataObject.OnGetProperty-like calls - this allows to check all security restrictions).

References to DataObject instances are still correctly tracked - e.g. you'll anyway get OnReference\OnDereference events if you'll add, change or remove an item holding the reference.

Robust instance removal process works also - e.g. you'll get a set of DataObject.OnSetProperty\ OnPropertyChanged or ValueTypeCollection.OnSet\OnSetComplete events on attempt to remove a DataObject instance referenced from structs stored in other DataObjects (or even in it).

DataObjects.NET doesn't store a value of struct passed to any of its method - it stores it in "exploded" (but enough compact) form except. This allows it to track changes in its parts, and thus persist just modified part of struct. Moreover, it's anyway necessary to hold a copy of struct rather then passed struct, it's impossible to track changes made to internal contents of the struct in this case. So you can consider that DataObjects.NET always holds its own copy of passed value.

Its possible to modify a part of stored struct or to get its part: you can use SetProperty("VisitCard.Address.City", value) notation to do this. Nevertheless you woudn't feel this in your OnSetProperty-like event handlers (method overrides), since DataObjects.NET always passes "fully combined" value and root property name to them. E.g. in this case you'll get usual OnGetProperty("VisitCard", culture, fullVisitCardValue) call.



[Translatable], [Collatable], [Indexed] attributes can be applied only on "root" properties (i.e. on properties declared in  DataObject instance only).

Use [Index("IX_My", new string[] {"VisitCard.Address.City", "VisitCard.Address.Street"})] notation to index a set of struct fields.

Apply all persistence-related attributes on struct fields rather then properties.

It's impossible to mark some of struct fields as [NotPersistent]. DataObjects.NET consider all struct fields as persistent.

It isn't important if some struct fields are private or internal - DataObjects.NET is capable to persist them anyway.

You can use [Alias] and [DbName] attributes to "rename" such private fields (usually private fields are named in "camel" style).

Currently you can't use [PairTo] attributes pointing to inner reference fields of structs.



ValueTypeCollections Are very similar to DataObjectCollections, but holds struct values rather then references to DataObjects.


Any ValueTypeCollection resides in the separate table (as well as DataObjectCollection). This table contains at least two columns: ObjectID and ItemID (both columns stores Int64 values, ItemID is autoincrement and primary key column), and two indexes (one on each column, the second index is unique). Other columns correspond to fields of struct designated by [ItemType] attribute that was applied on ValueTypeCollection field.


So as you see, it's possible to add multiple equal values to such collection - they'll anyway be distinguished by their ItemIDs.



Use [Index("IX_My", new string[] {"VCards.Item.VisitCard.Address.City""})] notation to index a set of columns in the ValueTypeCollection (it has VCards name in this example).

ValueTypeQueryResult instances are capable to push fetched items into collection's cache during iteration through them, so no additional queries database are executed during iteration (except queries fetching DataObject instances that holds these collections - remember, that anything "goes through" DataObjects). Nevertheless you can preload all of (or a part of) such instances by a single query using  ValueTypeQueryResult.PreLoad or Session.PreLoad methods.

QueryOptions.LoadOnDemand works differently with ValueTypeQueryResult - Query fetches only ObjectID and ItemID column values when it's used (so collection items will be fetched one-by-one during iteration through ValueTypeQueryResult). It's useful when it's necessary to process a part of large result set.


Next steps in studying these features:

See Demo_Articles sample for practical examples of use of structs and ValueCollections.

Refer to .CHM or .HXS help for additional information.


Tracking external changes of collections, caching of collection content

In this version of DataObjects.NET we introduced more efficient implementation of DataObjectCollection (and new ValueTypeCollection works nearly the same) - it supports 2 modes of tracking changes made by another transactions concurrently (DataObjects.NET should "transparently" show such changes), plus implemented partial caching of collection items.


Earlier all DataObjectCollection were tracking changes "through holder" - this means they were incrementing holder's VersionID on each change in the collection (nevertheless such "increment" was scheduling, but not immediately persisting). So collection becomes invalidated immediately with the holder on any external change of VersionID.


Now DataObjectCollection can track changes independently of its holder (so collection change doesn't lead to VersionID increment), but in this case cached contents of collection will be invalidated more frequently -  e.g. on completion of any outermost transaction. See [ChangesTracking] attribute description in .CHM help for addition information.


Newer implementation works efficiently also by another one reason - it's possible to divide all operations with DataObjectCollection (or ValueTypeCollection) into 2 groups:

First one includes all operations requiring to know element indexes (e.g. getting an element from collection by its index);

And the second group includes all operations that don't require to know these indexes (most of operations falls into this group).


Collections never load all items for any operation from the first group - usually they execute 0 or 1 queries in such case dependently on whether required item was already fetched (and thus cached), and always loads all items for any operation from the second group. Additionally an access to Count property was optimized - now it's fetched once at max between cache invalidations (zero, if the collection was already completely loaded - so Count is known).


Changes in DataObjectCollection type

We modified most of OnXXX methods in DataObjectCollection, since their former versions require item index as one of arguments.


Query improvements

It's easier to provide examples of new syntax here. New version of Query supports type casts:


Select Cat instances where exists{(Dog)Friends.(Mouse)Friends}


Description: selects all Cats having such Dogs in their Friends collection which have at least 1 Mouse in their own Friends collection (just a way to find a mouse for a cat J)


Joins and distinct (Articles is a collection: Author.Articles, "require" is the same as "inner join"):


Select distinct Author instances require Articles as $A order by {$A.PublicationDate}


Whole collection query:


Select (YellowBook)Author.Books items


Support of ValueTypes and ValueTypeCollections:


Select Author.Quotes values where len{value.Body} > 100


New attributes

There are 3 new attributes:

[Alias] - allows to specify synonyms for your type and class names;

[DbName] - allows to override auto-generated names of tables, views and columns;

[ChangesTracking] - specifies  ChangesTrackingMode for collections.


An example with [Alias] and [DbName] (both of them can be applied to any persistent properties or types):



public struct Vector


  [Alias("X"), Alias("a"), DbName("X")]

  double x;


  [Alias("Y"), Alias("b"), DbName("Y")]

  double y;


  public double X {

    get { return x;  }

    set { x = value; }



  public double Y {

    get { return y;  }

    set { y = value; }






Access control system improvements

Please, refer to the following sections in .CHM of .HxS help:

DataObjects.NET.DomainSecurityMode enumeration;

DataObjects.NET.Domain.SecurityMode property;

DataObjects.NET.Security.AccessControlList.Inherit property;

DataObjects.NET.Security.HashingMethod enumeration.


Note: We've changed the result type of IPermission.GrantedIfGrantedAnyOf {get;} method to ReadOnlyPermissionCollection - to eliminate inefficient, but necessary cloning of array. Most likely you should fix your existing code to conform the newer implementation - you should just change the types of corresponding properties and replace "new IPermission[] {...}" to "new ReadOnlyPermissionCollection(new IPermission[] {...})".


Sample updates

DoPetShop now supports editing of its catalogue. Login as "Administrator" and use "Admin" button to enter the management subpart.

A new sample was added: Demo_Articles, it shows new features of Query and utilizes ValueTypes and ValueTypeCollections.


Version 2.0.7

What's new

[Abstract] attribute allows mark some of your persistent types or services as abstract (necessity of this attribute has the same background as of [Sealed] attribute).

All DataObjects.NET attributes (types from DataObjects.NET.Attributes namespace) are now better described and has usage examples in DataObjects.NET Help (CHM and HxS).

"Building ASP.NET applications: DataContext and Global.asax overview" section is added to DataObjects.NET Manual.


[NonPersistent] attribute is renamed to [NotPersistent], [NonSerializable] attribute is renamed to [NotSerializable], [NonOverridable] attribute is renamed to [NotOverridable], DeclarationMode.NonPersistentByDefault is renamed to NotPersistentByDefault - we decided to correct names of these attributes and enumeration member. You can use search and replace with "Match case", "Match whole word" options to update the source code of your applications, it can take up to 10 minutes...

Principal.UserInfos property is removed, but UserInfo and UserInfoCollection types are available. You can declare the same property in your custom type, if this is necessary. We decided to remove this property since it seems not quite necessary, and finally, can be easily added to custom user type.

Domain.ConnectionURL and ConnectionInfo.URL allows using almost any possible characters in any part of URL except significant ones. Example of significant character is ":" in user name part - since it's a userName:password separator. Such characters should be URL encoded (formerly almost all characters except alphanumeric should be URL encoded).

Available Source Code Package is updated (it reflects all recent changes).

DataObjects.NET FAQ is updated.


Database model comparer incorrectly handles columns with AnsiVarChar type: if such a column exists in the database or model, it copies a whole table with such column (i.e. it copies a content of original table to temporary table, removes original table and renames a temporary table to the original table). The problem was in our column comparer: there was an error in its table of allowed typecasts, so comparer thought it's impossible to cast AnsiVarChar type to AnsiVarChar type (someone of us misprinted AnsiVarChar as AnsiChar). This also made impossible to use DomainUpdateMode.Block, if such a column were in the database. This error was introduced in DataObjects.NET 2.0.5 (where typecast table was added).

DataObjectCollection produced an exception on attempt to work with it, if it was paired to a collection declared in the persistent interface.

StdUser.IsDisabled property wasn't checked in the StdUser.Authenticate method.

We discovered that ASP.NET can execute a single web request in different threads (so methods of a single HttpApplication instance can be executed in different threads even for a single web request). This is very strange, since we didn't find anything concerning this in documentation, and unfortunately, bad: this means that code of DataContext class in DoPetShop and Demo_WebTransfers can work incorrectly, since DataContext.Session property can return incorrect Session object. This always leads to error because it returns a Session of another thread that is always closed on this moment. It's very difficult to meet this problem, and moreover, to reproduce it... So we located it only several days ago. E.g. this problem has never appeared on our DoPetShop performance benchmarks (it's difficult to say why, since we don't know how this behavior is implemented in ASP.NET). We've experienced it first on our web application that intensively uses hidden frames to interact with web server in background. The good news is that it can be solved easily: it's necessary to bind Session objects not to Thread instances, but to HttpApplication instances. These changes are already made to DoPetShop's and Demo_WebTransfers' DataContext.cs files. If you're using DataContext-like class in your web application, you should perform the following actions to fix the problem: replace any "Thread.CurrentThread" string to "HttpContext.Current.ApplicationInstance", and add "using System.Web" line to the list of using directives.


Version 2.0.6

This version introduces set of very noticeable performance optimizations.

What's new

Full version of DataObjects.NET is now shipped with Not Remotable Version of DataObjects.NET additionally. Any MarshalByRefObject descendant in the normal version is replaced by Object descendant in this version (except Domain - it's still a MarshalByRefObject descendant, just for compatibility).

MarshalByRefObjects consume additional memory, that primarily impacts on performance. The more memory application consumes, the less efficient L1\L2 caches become.

Non-virtual methods of MarshalByRefObjects are invoked nearly with the speed of virtual methods.

Non-virtual methods of MarshalByRefObjects aren't expanded inline by CLR.

This makes Not Remotable Version of DataObjects.NET 5-10% faster.


Note: the presence of this version doesn't mean you have to choose between performance and ability to use your objects remotely. You can achieve both goals by using both DataObjects.NET versions, but in different application domains (it's impossible to load two these assemblies into a single application domain - they contain same type names).


For example, in case with ASP.NET application you can use Not Remotable Version, and run the normal version in separate application domain - solely to marshal a single Domain object working with the same persistent model as ASP.NET application. DataObjects.NET allows using any number of Domain instances having completely identical configuration (the same persistent types model and the same database) simultaneously - in the same application domain or on another PC. So nothing prevents to use two Domain objects - one for in-process use (running on Not Remotable Version of DataObjects.NET), and another (running on a normal version) for remote clients.


A redundant stack check code was removed from TransactionController class. This update has very noticeable positive impact on performance - TransactionController objects are used almost everywhere (it's a key component in automatic transactions support). You can read more about this further.

DataObject.OnBecomeDirty event was removed. As it was mentioned earlier, the presence of this event wasn't completely necessary, but its support requires additional processing of cached objects table on each rollback, that can be slow enough. It was thought to be used in aggregate property caching scenarios (for example, to cache values of properties like Principal.AllRoles). Any such property caching scenario can also be implemented with use of TransactionContext object - currently this is the only available way. See Principal.cs class in Available Source Code Package for example of such property caching code.

TransactionContext.State property (and corresponding enumeration) was added - it simplifies implementing property caching scenarios.

Principal code was updated in accordance with new property caching schema.

DataObject class code was slightly optimized - most of foreach statements were replaced to for statements (locating current element by its index). Any foreach statement execution allocates new enumerator (IEnumerator), so in many cases they work slower than simple for with indexing. Generally this rule works well for all Array and ArrayList-based collections.

SessionSecurityOptions.AllowUseFastLoadDataOff option was removed - currently it's rather difficult to imagine the situation where use of this option can be absolutely necessary.

DomainSecurityOption.AllowCreateUnauthenticatedSessionsRemotely option was added.


Extended explanation on TransactionController - related update:


We introduced TransactionController in DataObjects.NET 1.8.1 - to ensure that no one can commit any inner or outermost transaction without a permission to do this. An example: some persistent object (DataObject) or service (DataService) executes a transactional operation; than it makes a call to some possibly malicious code (e.g. it invokes some event handler). This code can commit its transaction (because usually it can access the Session object) - this is generally a violation of business rules (partially finished operation -> data inconsistency). Security system can't help to solve this problem, because actually it acts on upper layers. Notice, that a transaction rollback is not a problem in this case - any code can rollback a transaction, because this doesn't lead to data inconsistency.


So it's necessary to prevent this situation. TransactionController object is devoted to doing this. Any TransactionController instance is actually an object that acts like "key" - if you have a reference to it, than you can commit a transaction it controls (it Locks this transaction and encapsulates unlock code). This is the solution.


But we decided to make this type even more safe - TransactionController was checking the stack on its construction and execution of its Commit\Rollback methods to prevent attempts to commit a transaction by a malicious code that can work only upper in the stack (so it was checking this situation additionally).


This code was extremally slow (it was possible to perform ~ 50000 such checks per second), and moreover, it was unnecessary... Since if a method is coded correctly, it will never pass its TransactionControllers to malicious callers, so the only way to get them is to use the reflection, but if a malicious code has a permission to use reflection, it can hurt any application by set of much easier ways. So we simply removed this code from TransactionController.


Why this small part was seriously slowing down the whole application? TransactionController objects are used in automatic transaction handlers, so any method having [Transactional] attribute  with  TransactionMode!=TransactionMode.Disabled argument has its own TransactionController to ensuring the safety of method execution. E.g. GetProperty\SetProperty methods are marked by a [Transactional] attribute, so this type was used even in any persistent property get\set operation. This is the answer.


Current implementation works much faster: now DataObjects.NET is capable to perform:

Persistent property read operations with complete permission checks: up to 750000 per second on AthlonXP 2,1GHz. Our test was reading Item.Qty property of a single object from DoPetShop catalogue;

Permission checks (demands): up to 3000000 per second on AthlonXP 2,1GHz. Former result was 2000000 on P4 2,8 GHz. Our test was demanding 3 random permissions on random objects from DoPetShop catalogue.

Version 2.0.5



All .PDF documentation was bundled into CHM and Html Help 2 files.

This version of DataObjects.NET is shipped with Html Help 2 version of documentation (see Help folder).


Performs complete configuration of sample web applications (DoPetShop and Demo_WebTransfers), including creation of two virtual folders and setting appropriate permissions.

Performs registration of Html Help 2 documentation in the Visual Studio .NET 2003 Help Collection. This allows using all Visual Studio .NET Dynamic Help features (context-sensitive help) with DataObjects.NET Help.

Database schema update layer was improved - column type\property change actions keep source column contents in set of additional cases, e.g. when the target SQL type of column is different but compatible, and the size is the same or extended.

Trial version evaluation period was reduced to 21 days.

Version 2.0.3


Now DataObjects.NET automatically adds an index for any field of type DataObject (or of type of its descendant). It's always necessary to index such fields, because DataObjects.NET can execute a query with condition on these fields, for example, during the removal of some other instance (see Robust Instance Removal Process section in DataObjects.NET Manual).

It's possible to specify an SqlCollation for the particular Culture manually (see new overloads of Culture constructor).

Set of additional SQL Server collations is supported:












































































DataObjectCollectionBase.CreateQuery could produce a Query with incorrect join\restriction condition: two internal methods of QueryBase (ApplyJoin\ApplyRestriction) used by CreateQuery didn't properly mark a query as "requiring translation to command". Because of that join\restrictions were taking effect only if a query-to-command translation was requested by some other part, e.g. when a Count option wasn't specified, but an ExecuteCount() method was used to execute the query (the translation to command is also requested while new effective options (Options | QueryOptions.Count in this case) are temporarily taking effect).


Version 2.0.2

This version primarily introduces the set of performance and stability improvements.

What's new

Two more restrictions were added to the Trial version:

DataObjects.NET begins to significantly slow down its overall performance if it discovers that there is a DataObject instance with ID>100000 in the storage.

Support of Int16 (short) and Byte (byte) data types was completely removed from the Trial version.

Permissions are now stored in the more compact way. Former permissions format is recognized, but DataObjects.NET will update such permissions to the new format automatically.

Permissions loading and validating mechanism was significantly improved - current version executes only one additional query (if required) to load and validate all security principals related to some ACL.

Session.GetObjectCachingState(...), Session.PreLoad(...) methods were added. You can find more information about them in the DataObjects.NET CHM Help.

DoPetShop Remoting Client was updated - now it demonstrates an approach that can be used in the real-world applications.

New Wrappers use property caching to reduce the number of remote invocations.

The WrapperFactory class was added. Its purpose is to provide a single wrapper for a single DataObject instance in each Session.

It uses optimistic locking based on DataObject.VersionID property.

It informs the user about all update errors and conflicts.

You'll notice the presence of these improvements after 5 minutes of its usage!

We can add that there are lot of ways for further improving its performance - for example, it's possible to reduce the number of remote calls by "combining" set of multiple calls into one (this way can be used to obtain a bulk of property values/object sets) and optimize its transactional behavior. Nevertheless we think its current version provides an approach that is completely acceptable for non-remoting GUI applications at least.

DoPetShop was updated:

SecureMode configuration parameter was renamed to MaxmialSecurity;

DataPump class was replaced with DataPumpService.

Permission checks were highly optimized: currently DataObjects.NET is capable to execute up to 2000000 permission demands per second on 2,8GHz P4! This result was obtained by the following way: the testing application was calling DataObject.IsAllowed(...) method on a random object from DoPetShop and with a random permission (all actions were performed in a single transaction, of course).


So now we can announce that DataObjects.NET 2.0 offers the same or even better performance as 1.8.1, but providing the most powerful security system available on this market! The performance decrease should be noticeable only on the very short transactions or sessions (i.e. where up to 5 objects are accessed - for example, DoPetShop primarily executes such transactions, but nevertheless it operates only 20% slower on DataObjects.NET 2.0).


Session.IsCached(...) method was renamed to Session.IsObjectCached(...).

Instance and instantiation data caching was improved.

Support of UInt64, UInt32 and UInt16 data types was removed. DataObjects.NET is primarily targeted on SQL Server support, but it has no corresponding data types (Oracle and SAPDB were able to handle them as numeric(N)).

DataObjects.NET CHM Help and Manual were updated.


DataObject.Remove method now temporarily disables security system (see SessionBoundObject.DisableSecurity) after OnRemove invocation and till the OnRemoved invocation. The block with disabled security performs the following:

Resets all reference fields of the removing instance to null;

Clears all collection fields;

Removes contained instances (see [Contained] attribute);

Resets all external references to the removing instance.

If the security system is enabled during execution of this part, it makes possible that:

A reference field, on which SecurityParent property depends, will be reset (set to null), so SecurityParent of removing object will be changed (and effective permission set will be changed - consequently). This can prevent execution of the other steps.

Current user may haven't enough permissions to execute steps 3 and 4 (e.g. it may have no RemovePermission on some contained instance, or may have no ChangePermission on some instance that refers to the removing instance), but generally this shouldn't prevent him from completion of Remove method, because he have major permission (RemovePermission) allowing him to perform this.

Observable side effect of this error was impossibility to remove the item from cart in DoPetShop (its SecurityParent was changing to SecurityRoot on step 1).

An error in the DoPetShop's ShoppingCart.aspx.cs code was fixed: it was incorrectly updating quantities of upper items on the page if a zero or negative quantity was specified for some item. See removedItemsCount variable usage in the code to understand the problem better.

DataObject.OnBecomeDirty event (virtual method) was added. The presence of this method allows to perform cached data invalidation on the transaction rollback. This also means that Principal.AllRoles value caching introduced in the DataObjects.NET 2.0 was incorrectly handling the situations like:

The CorporateUsers Role includes the DevelopmentDepartmentUsers Role;

A new outermost transaction was started in some Session;

The DevelopmentDepartmentUsers Role was fetched (accessed);

A new inner transaction was started in the same Session;

The CorporateUsers Role was fetched (accessed);

The AllRoles property of DevelopmentDepartmentUsers was accessed (consequently its value was cached);

A CorporateUsers Role was added some other Role (e.g. EnterpriseUsers), so cached AllRoles value of DevelopmentDepartmentUsers was invalidated by RolesChanged notification from CorporateUsers Role;

The AllRoles property of DevelopmentDepartmentUsers was accessed again (consequently its value was cached again);

The innermost transaction was rolled back. DataObjects.NET 2.0.2 invokes OnBecomeDirty method on any object containing a dirty data in this case, so cached AllRoles value of DevelopmentDepartmentUsers will be invalidated by notification from CorporateUsers Role (this notification is raised by the OnBecomeDirty method of the CorporateUsers Role). But DataObjects.NET 2.0 doesn't supports this notification, so no invalidation will occur in case with DataObjects.NET 2.0;

The AllRoles property of DevelopmentDepartmentUsers was accessed again - in this case DataObjects.NET 2.0 would return incorrect cached value of this property (that includes EnterpriseUsers Role). DataObjects.NET 2.0.2 handles this situation correctly.

Note: Use of OnBecomeDirty event isn't the only way of handling such situations - e.g. it's possible to additionally store the Session.TransactionContext value during the property caching, and check its IsDirty property before returning the cached value (it should be refreshed if the stored TransactionContext is marked as dirty). You can choose between these two methods of correct calculated property caching implementation.

TransactionController.Commit\Rollback thread check condition could fail if these methods were invoked via .NET Remoting. This mistake could lead to impossibility to commit a transaction controlled by this object in the .NET Remoting scenarios.

TransactionController now doesn't consider a call from System.Serialization.Formatters.Soap assembly as unsafe, so it doesn't begin a new inner transaction for each of such a call. This slightly improves SOAP serialization and deserialization speed (primarily because this reduces a number of additional queries required to establish the savepoints for inner transactions).

Set of UpdateAction descendants were using Hashtables and ArrayLists describing the UpdateAction. It was possible to modify the content of these collections in the already built Domain. Such an operation has no effect on DataObjects.NET itself (because it never uses UpdateActions collection after completion of the Domain.Build method), but it could confuse the application that studies Domain.UpdateActions, e.g. to detect if it's necessary to perform some additional operations. Currently corresponding properties of these objects always returns new clones of their internal collections.

An error in IntField class code was making impossible to use Short and Byte types as types of persistent properties.

Set of non-factual mistakes in the DataObjects.NET Manual was fixed.


Version 2.0

We wish Happy New Year to all our customers and clients! We really appreciate your attention to our products and services. We wanted to make you a bit happier in the beginning of the New Year releasing DataObjects.NET 2.0.

What's new

Please, read the Summary first - nearly 40% of the whole Revision History covers new features of DataObjects.NET 2.0!


New features summary:

Built-in security system - DataObjects.NET 2.0 introduces extremely powerful security system allowing to define the permission for any action (e.g. method execution or property access), allow or deny it for set of security principals (users and roles) on some persistent instances (like on folders in NTFS) and enforce the execution of security rules by demanding this permission in the methods\properties code. Its primary goal is to make the usage of business objects completely safe, even when these objects are publicly available (e.g. when the Domain instance is marshaled via .NET Remoting, and its URL is well-known).

Persistent interfaces support;

Runtime services;

Improved full-text indexing and search;

Improved serialization layer;

Samples were seriously updated:

DoPetShop uses most of new concepts - security system, persistent interfaces, runtime services, new full-text search and serialization features;

DoPetShop RemotingClient uses WindowsForms DataGrid control allowing to navigate through the whole DoPetShop's catalog and even edit it! Its size (without the InitializeComponents method - it's usually "coded" by VisualStudio.NET) is only 25 Kb.

All other samples was slightly updated;

DataObjects.NET 2.0 becomes available in Enterprise Edition with the complete source code (note that this edition is available under different License Agreement).

A part of DataObjects.NET 2.0 source code (Available Source Code Package) is shipped even with the Trial version (primarily to simplify the usage of DataObjects.NET 2.0 and to allow end users to understand its concepts faster and better);

Several stability-related improvements (primarily covering database schema update process) are implemented;

And finally, 30% discount is provided for any person or company purchasing DataObjects.NET during the last 3 days of this year!


Comprehensive description:

Compatibility notice: DataObjects.NET brings set of very significant improvements, nevertheless DataObjects.NET 1.8.1 - compatible applications will require very limited set of changes to start on DataObjects.NET 2.0. Primarily the following actions should be performed to achieve this:

Full-text indexing and search - related issues:

Replace "using DataObjects.NET.Library" to "using DataObjects.NET.FullText" (namespace was changed);

Replace "FullTextIndexedObject" to "FtObject" (class was renamed);

Replace "GetFullTextData" to "ProduceFtData" (method was renamed);

Add a code that adds FtIndexer service to Domain.RuntimeServices collection;

Fix textsearch clause in Queries, and FullTextSearchCondition in SqlQueries (new format is described in the DataObjects.NET CHM Help);

Other issues:

IDataObjectField interface is changed - it was extended by one additional method: FieldContentChanging. You should implement this method in all classes that supports this interface (see Demo_Animals for example).

Remove all [PersistOnChange] attributes (PersistOnChangeAttribute is removed);

Replace "OnDeserialize" to "OnDeserializing" (method was renamed).

Don't worry about compatibility with the new security system - Domain will create default system security objects automatically on its startup, also by default it allows to create unauthenticated (insecure) Session instances (see DomainSecurityOptions enumeration), so no additional changes should be performed in this case.


Security system: DataObjects.NET 2.0 introduces extremely powerful security system allowing to define the permission for any action (e.g. method execution or property access), allow or deny it for set of security principals (users and roles) on some persistent instances (like on folders in NTFS) and enforce the execution of security rules by demanding this permission in the methods\properties code. Its primary goal is to make the usage of business objects completely safe, even when these objects are publicly available (e.g. when the Domain instance is marshaled via .NET Remoting, and its URL is well-known).
Key conceptions of the security system:

Immediate effect: all security restrictions take effect immediately on any security-related changes in the Session - for example, it's not necessary to reopen the Session or to invoke some method to apply new security restrictions. When you adding a User to some Role or denying some permission for him or for some role it belongs to, this immediately affects on its security restrictions in the current Session. So all is transparent even in this case. Even a rollback of the inner transaction (or a rollback to the savepoint) immediately affects on security restrictions.

Any DataObject instance contains its ACL (access control list). ACL is set of per-Principal allow-deny permission sets (see IPermissionSet and PermissionSet descriptions in the DataObjects.NET.chm). Any permission, that isn't mentioned in the ACL for a particular Principal and for any Role this principal belongs to (directly or indirectly - i.e. user Alex indirectly belongs to the MyCompanyWorkers role, when it belongs to the DevelopmentDepartmentWorkers role, and this role belongs to the MyCompanyWorkers role) is inherited from its SecurityParent object. So from the point of DataObjects.NET security system your business objects are organized into the tree structure with the ISecurityRoot (see Session.SecurityRoot) object in its root.

As it was mentioned, there are some pre-defined (but extendable) persistent classes:

Principal is the base class for any security principal. Any principal can belong to the set of Roles and has unique Name. It's possible to get AllRoles collection of any principal (a set of Roles to which it belongs directly or indirectly) and test, if a particular Principal belongs to the specific Role (see IsInRole method);

Role (Principal descendant, to which some other principals can belong). Any Role maintains its Principals collection (actually this collection is simply paired to Principal.Roles collection). As you may noticed, DataObjects.NET makes such paired collections automatically synchronized - so you can add a Principal to some Role by two equivalent (but different in the notation) ways: principal.Roles.Add(role), or role.Principals.Add(principal);

User (it's a Principal descendant too) is base class for any security User. This type introduces Authenticate method (an abstract method that should be implemented in its descendants - this allows you to implement your custom authentication schemas) and two events: OnAttachToSession() (called when a particular User becomes the current User in the Session) and OnDetachFromSession. These events allow to perform custom actions when the User becomes current in the Session (current user is a user, for which DataObjects.NET performs permission checks) - e.g. it's possible to additionally impersonate the current Thread to the specific Windows account in such case.

StdUser (User descendant) - it's the ready-to-use User implementation (so it implements Authenticate method). This type of user supports authentication by the string of characters (i.e. by the password). This type also introduces SetPassword(...) method (see its description and code to understand its behavior better - the code of almost all mentioned classes is shipped with DataObjects.NET 2.0). This type supports the following formats of storing a password: Plain, MD5 hash, SHA1 hash and SHA256 hash. All default system users (System and Administrator) created by the Domain are instances of this type (nevertheless you can override even this - you should implement you own Domain.InitializeSystemObjects event handler in this case).

IPermission is a non-persistent interface that should be implemented by any security permission type. Any instance supporting this interface should be serializable to allow DataObjects.NET to store it. It defines the following primary methods: Copy, IsAllowed, Demand.
Demand and IsAllowed methods should simply call the same methods on the object that was passed to them (ISecureObject). Also any permission should be immutable (except IPermissionSets - they are IPermission descendants too). And finally, DataObjects.NET considers two permissions as equal, if these types are equal, and they aren't IParameterizedPermission or IPermissionSet descendants (so particular IPermission instance actually has no meaning - any IPermission should be a singleton, but we decided to not use this pattern here primarily to simplify the coding of custom permissions).

Permission is default IPermission implementation. There is a set of pre-defined permissions supported internally by DataObjects.NET:

AdministrationPermission - this permission is supported internally by DataObjects.NET.

It allows to perform anything - any permission Demand will be successful if this permission is allowed.

ChangeFullTextDataPermission is required to change any full-text indexing data (see IFtObject, FtRecord);

ChangePasswordPermission is required to use SetPassword method for the particular StdUser;

ChangePermission is required to change any property of the DataObject instance;

ChangePermissionsPermission is required to change the Permissions property of the DataObject instance;

ChildrenDeserializationPermission is required to deserialize child objects of the DataObject instance;

ChildrenPermissionsDeserializationPermission is required to deserialize child objects' permissions;

OwnerPermission - the presence of this permission for a specific user (or group) tells that he is an owner of the DataObject instance (actually it implicitly grants ChangePermission, ChangePermissionsPermission, ReadPermission, ReadPermissionsPermission, RemovePermission, ChildrenDeserializationPermission, ChildrenPermissionsDeserializationPermission, SerializationPermission).

SerializationPermission is required to serialize the DataObject instance;

ReadPermission is required to read any property of the DataObject instance;

ReadPermissionsPermission is required to read the Permissions property of the DataObject instance;

RemovePermission is required to remove the DataObject instance.

Note: because any permission is immutable, it's possible to introduce the static Value method in each permission type returning the pre-created (default) instance of this permission (this is just a performance consideration).

Note: most of these permissions are checked in the DataObject.OnXXX virtual methods, so you can override the enforcement of pre-defined permissions in your business objects!)

IParameterizedPermission is an interface for any "parameterized" permission. Any parameterized permission should actually represent a permission set where the number of elements isn't determinable, but nevertheless it's possible to perform Union, Subtract and IsSubsetOf operations with such a set. Instances of this type should be immutable too. There are no built-in parameterized permissions in the DataObjects.NET.

IPermissionSet represents the set of permissions. It introduces Clear, Union, Subtract, IsSubsetOf and IsSupersetOf methods.
IPermissionSet instances can be used anywhere where the IPermission instance can be passed (e.g. you can pass an IPermissionSet instance to the Demand method).
IPermissionSet isn't immutable - we decided to do this because of performance considerations - it's not a good idea to create a new permission set every time when it's necessary to modify some permission set.

PermissionSet is its ready-to-use implementation. Note, that this type properly overrides ToString() method.

ISecureObject is an object on which an IPermission can be demanded. There are two ISecureObject implementers in the DataObjects.NET: DataObject and Session. Actually Session "forwards" any permission demands to Session.SecurityRoot object (it is the DataObject and ISecureRoot descendant, the root node in the security inheritance hierarchy).

ISecityRoot is an interface that should be supported by the DataObject instance that can be used as the root object in the permission inheritance hierarchy. This is a tagging interface - DataObject.NET uses it to find the root object.
Note: only one instance supporting this interface can exist in the storage.

AccessControlList class - it's the class that actually stores permissions and performs permission checks. It is accessible through Permissions property of the particular DataObject instance. It provides the following methods: Allow, Deny, RemoveAllowed, RemoveDenied, ResetPermissions, ResetChildPermissions, IsAllowed, Demand, GetAllowedPermissionSet, GetDeniedPermissionSet, GetEffectivePermissionSet methods. This type also properly overrides ToString() method.

DataObject class introduces set of new methods (IsAllowed, Demand) and properties (SecurityPerent, SecurityChildren and SecurityRoot).

Session provides Authenticate method, User and SystemObjects properties (see its SecurityOptions also).

Domain introduces set of security-related events and SystemObjectNames property (see its SecurityOptions and SessionSecurityOptions also).

Finally there is a SecurityException class - instances of this type are used to inform about security-related exceptions.

Refer to the DataObjects.NET Manual and DataObjects.NET CHM Help for the further information. Also we recommend you to study the source code of XXXPermission, Principal, User, Role and StdUser classes, and move to the DoPetShop sample further.

Persistent interfaces support: now it's possible to use persistent interfaces (IDataObject descendants) -these interfaces are supported by queries and reference/collection fields. You can:

Subclass the IDataObject interface to define your own persistent interface;

Apply persistence-related attributes to some (or all) of its properties by the same way as for DataObject descendants;

Implement this interface in some of your persistent classes (you should use apply the same persistence-related attributes to implemented persistent properties, or ensure compatibility of underlying database types);

Use such interface as type of reference fields (e.g. declare persistent fields like: public IPerson parent) or collection items (e.g. use [ItemType(typeof(IAnimal))] attribute declaration).
Note: you can use
PairTo and Symmetric attributes even within the persistent interfaces;

Specify persistent interface type in query (see Query.Text or SqlQuery.InstanceType) - in this case the query will select all objects implementing specified interface and satisfying the query criteria. Example: "Select IAnimal instances where {LegCount}=4" - selects all objects that support IAnimal interface and have four legs (LegCount is a persistent property declared in the IAnimal interface);

And, of course, you can use persistent interfaces by all other ways (as normal interfaces) supported by the .NET Framework.

Brief implementation description:

DataObjects.NET builds a separate view for each persistent interface that selects all persistent fields of this interface (for each instance that implements this interface). The definition of this view uses union and inner join expressions to consolidate the data located in several different tables. So usage of such a view in queries is C times more expensive when use of class-related views, where C is the number of tables consolidated with the union keyword (it equals to the number of base classes implementing the interface, in the most of cases C = 2...5), so the cost of "interface queries" is nearly the same as the cost of "class queries".

Also a separate view (by the same schema) is built for each persistent collection (and for each Culture registered in the Domain - in case when a property is marked by [Translatable] attribute) declared in persistent interface.

Additionally a single table is built for each persistent interface (and its collections). These tables are never used to store the data (so they are always empty). The only their purpose is to "describe" related interfaces. This allows DataObjects.NET to update the database properly when interface definitions will be changed.

And, of course, DataObjects.NET now supports persistent interfaces internally. E.g. we extended DataObjects.NET.ObjectModel classes by a set of properties, added support of this feature to the ObjectModelBuilder, DatabaseModelBuilder, ProxyBuilder, QueryBase, Query, SqlQuery, references and collections-related classes, etc...

Runtime services are DataServices of special type (RuntimeService descendants) that can be periodically executed in the separate Thread and Session maintained by the Domain. The purpose of runtime services is to perform any maintenance tasks periodically. An example of such service is FtIndexer (read further) that periodically updates full-text index data. One more example is CleanupService in the DoPetShop. The purpose of this service is to remove the carts of user that left the site. Previously its execution was managed by the DoPetShop itself, but now it's completely handled by DataObjects.NET.

Implement RuntimeService descendant to create a custom runtime service;

Use Domain.RuntimeServices.AddRuntimeService method to register a new runtime service in the Domain. Note that this method can be invoked only before Domain.Build(...) method execution.

Note: the code of FtIndexer is included to the Available Source Code Package, so you can study it as the example of runtime service.

Improved full-text indexing and search: use new DataObjects.NET.FullText.FtObject class or DataObjects.NET.FullText.IFtObject interface to implement your own full-text indexed objects. These types provide better full-text indexing capabilities:

Each IFtObject implementor (and FtObject descendant) contains no full-text data itself, but it sets its FtDataIsUpToDate field to false on each update operation. This allows FtIndexer service (RuntimeService descendant) to determine which of full-text indexed objects were changed.

FtIndexer updates full-text data for each of such instances periodically (see its OnCreate method for more information). Full-text data is stored separately in the FtRecord objects.
Note: you should have PermissionAdministration to access FtData property of these objects - this prevents studying the contents of this property by a normal users.

Full-text queries now use the data stored in these objects if full-text search condition is specified.

Also a new search mode was added: FullTextSearchMode.LikeExpression. This mode allows to search through FtData even when there is no full-text search available (e.g. when working with SAP DB). See Demo_Books for example of using this mode.

Note: format of Query.Text property was changed (now it's not necessary to specify the type and column in the textsearch clause).

Note: the code of FtIndexer, FtObject and FtRecord is included to the Available Source Code Package - try to study them (e.g. FtIndexer is only 4,5 Kbytes of code).

Improved serialization layer: updated serialization layer provides the following additional features:

It completely supports DataObjects.NET security system (look SerializationOptions and DeserializationOptions enumerations and set of default permissions);

It supports additional events: DataObject.OnCreateDeserializable, DataObject.OnGraphDeserialized;

It provides AdditionalInfo property (it can be used during the deserialization, e.g. to change parent objects of some deserialized instances);

A new SessionSecurityOption was added: AllowUseSerializer.

It's free of errors that were found in DataObjects.NET 1.8.1 serialization layer.

Note: new serialization format isn't compatible with the DataObjects.NET 1.8.1 serialization format. You should persist the serialized graph to the database (deserialize it) on DataObjects.NET 1.8.1 and serialize it back on DataObjects.NET 2.0 to convert your serialized data to the new format.

Samples were seriously updated:

DoPetShop sample:

Shows basic security features of DataObjects.NET:

Implements its own StdUser descendant (Account) holding additional information about the DoPetShop user account;

Implements Domain.InitializeSystemObject event handler performing substitution of pre-created Administrator and Anonymous User accounts (these pre-created system objects are StdUser instances, DoPetShop replaces them to corresponding Account instances);

Authenticates DoPetShop users via DataObjects.NET security system to enforce their security restrictions;

Establishes SecurityParents hierarchy overriding this property in almost each type (e.g. any Product has a Category where it's stored, this Category is a SecurtyParent of this Product and so on);

Pre-creates "Restricted User" Account - a ReadPermision is denied on "Reptiles" Category for this account. This means that any Product or Item located in this category isn't accessible for this account - an SecurityException will be thrown (don't worry - it's a normal situation, because we don't intercept this exception) on any page where this restriction takes place - e.g. it can be thrown even on Search.aspx page, if a Product from "Reptiles" Category should be displayed.

Adds and enforces 3 new permissions: ChangeAccountPropertiesPermission, ReadAccountPropertiesPermission and TakeAnonymousCartPermission.

Reuses Session instances during subsequent web requests - this allows DataObjects.NET to use cached objects in the consequent web requests. Formerly a new Session instance was created per each web request.

Provides two updated "template" files: Global.asax.cs and DataContext.cs. Updated code supports new security concepts (e.g. authentication and impersonation) and provides some additional features (e.g. Sessions reusing). We recommend using the code of these files in your applications at least at the beginning.

Shows new full-text indexing and search features:

DoPetShop adds FtIndexer service to Domain.RuntimeServices collection on its startup. This service updates full-text data (related FtRecord object) of every modified instance once per minute.

Most of DoPetShop Model classes are now FtObject descendants; some of them (Product, Category, Item, Supplier) overrides ProduceFtData method. This allows to search through any of these instances, but we decided to do not change the functionality of Search.aspx page, so it's possible to search only Product instances (as it was possible formerly).

Nevertheless new SearchService provides two search methods: SearchProductsByKeyword (it's a new implementation of former search method that uses DataObjects.NET full-text search feature (with textsearch clause) to search products and order them by a FullTextRank value. This method calls SearchProductsByKeyword_Simple method (that performs old-style search), if full-text search service (Microsoft Search) isn't available (e.g. when it's stopped or different database server is used). This ensures that products search will work anyway.

Uses persistent interfaces:

IPerson interface (implemented in Person and Account class);

ITopLevelObject (implemented in Account, Category and Supplier classes), see DataPump.cs for examples of its usage.

Shows RuntimeService usage:

It uses two runtime services: FtIndexer (already mentioned) and CleanupService (this service periodically removes carts of users that have left the site).

Shows new serialization concepts:

See DataPump class - it's used by DoPetShop to populate its catalog. It provides 4 methods: EmptyDb (removes all non-system objects from the DoPetShop database), PopulateDb (populates the whole DoPetShop catalog by manually creating all its objects; also this method creates "Restricted User" account and denies a ReadPermission on "Reptiles" category for it), SerializeDb (serializes DoPetShop catalog and all non-system user accounts; note that permissions are serialized too) and DeserializeDb (simply deserializes specified XML file into the DoPetShop database, with all permissions).

Note: most of mentioned features are supported primarily by the DoPetShop Model that was significantly changed: its initial size was 17 Kbytes, currently it contains 51 Kbytes of code. So it grew up, but notice, how many new features it supports now! And imagine, how many times should grew original Microsoft .NET PetShop Model to provide similar features (initially it was ~ 140 Kbytes).

DoPetShop RemotingClient sample:

Supports DoPetShop authentication: two additional fields (user name and password) should be filled before clicking on "Go" button;

Utilizes SearchService to search the products by keywords (as it was formerly);

Uses WindowsForms DataGrid control to display the list of found products;

Allows to navigate (move to the related instances, e.g. from any Product to its Category and Items, from any Item to its Supplier and so on) through the whole DoPetShop's catalog. Try to press "+" sign placed oppositely to the product;

And even allows to edit it! You can do this only when you are logged in as Administrator - that's one of examples of how DataObjects.NET security system enforces security restrictions - RemotingClient contains no any code checking this permission, it's enforced completely by DataObjects.NET.
all editing changes are persisted immediately, but FtIndexer updates full-text data once per minute, so you should wait before your changes become available for full-text search. Also remember that DoPetShop's Search.aspx caches search results (for 10 minutes) by the same way as it was implemented in its original.

You should try to log in as Restricted User and type "cat iguana" in search keywords ("Iguana" is a product placed in the "Reptiles" category, that isn't allowed for Restricted User) to see that DataObjects.NET enforces ReadPermission in this case too.

It sends a web request to the DoPetShop's Default.aspx page before connecting to the Domain to make IIS to start DoPetShop (if it isn't running yet). Further it repeats this request to prevent its possible shut down.

Its size (without the InitializeComponents method - it's usually "coded" by VisualStudio.NET) is only 25 Kb.

Note: we used set of small "wrapper" classes to bind DataObject instances to the DataGrid, these classes are required primarily to handle security exceptions (e.g. these classes returns "(unavailable)" value from string properties when a SecurityException is thrown on attempt to read the corresponding property of "wrapped" DataObject instance). You can bind a collection of DataObjects to the DataGrid without any wrappers when it's not necessary to handle these exceptions, and it's not necessary to use the navigation (an ability to move to the related instances in the same DataGrid). You can find more information about binding a collection of custom types to the DataGrid here: MSDN Library, DataGridTableStyle.MappingName property description.

All other samples was slightly updated;

A set of events was added to the Domain type (primarily this is the requirement of the security system):

Initialize - occurs before completion of the Build method. This event is raised after InitializeSystemObjects event;

InitializeSystemObjects - occurs before completion of the Build method. This event is raised before Initialize event;

SessionCreated - occurs on the Session instance creation;

UserAuthenticate - occurs before User authentication in the Session;

UserAuthenticated - occurs when successful User authentication in the Session takes place;

UserAuthenticationFailed - occurs when unsuccessful User authentication in the Session takes place;

UserChange - occurs before changing active User in the Session;

UserChanged - occurs on successful change of Session.User property value.

Note: you can add event handlers of these events only before Domain.Build(...) invocation.

DataObjects.NET 2.0 performs database update in a single transaction when it's possible. Microsoft SQL Server doesn't allows to execute full-text indexing-related commands in transactions, so such commands "split" the single update transaction into set of transactions. But update will be performed in a single transaction, when any of the following conditions is true:

An Oracle or SAP DB database driver is used;

Microsoft Search service is stopped;

Update doesn't touches FtRecord-related table (that is almost always true).

Formerly any SQL command have been executed in the separate transaction during update process. New behavior makes update process safer and allows to reproduce the failure conditions, when an error takes place during the update.

New FastLoadData format is introduced: see DomainFastLoadDataFormat enumeration. Former format is fully supported (currently it's called as Compact).

DataObjects.NET 2.0 outputs one additional file - DomainBuildLog.txt in the debug output mode (see Domain.DebugInfoOutputFolder), that contains detailed information about the domain building process.

Some additional, but small improvements (see Session.InconsistentDataUpdateProbability, DataObject.IsCreating, TransactionController) are implemented.


Two new events are added to the DataObjectsCollectionBase: OnChange() (fired before any changes in the collection) and OnChangeComplete() (fired after the collection was changed).

IDataObjectField interface is changed - it was extended by one additional method: FieldContentChanging. You should invoke this method before changing the contents of fields that supports IDataObjectField interface.

DataObject.OnPropertyDeserializationError event added.

DataObject.OnDeserialize(...) event is renamed to DataObject.OnDeserializing(...).

PersistOnChangeAttribute was removed (currently VersionID property of DataObject instance is always automatically increased on changes in any persistent property that implements IDataObjectField interface).

ProxyBuilder now marks all proxy classes as sealed.

Several performance-related updates were made.

DataObjects.NET.chm was seriously updated.

DataObjects.NET Manual was seriously updated - e.g. it explains DataObjects.NET security concepts and provides new Queries Tutorial;

FAQ & Readme were slightly updated.


DataObjectCollection.CreateQuery(...) produced invalid join condition for paired (see PairToAttribute) and symmetric (see SymmetricAttribute) collections;

DataObjectCollectionBase.Clear() method didn't notified paired collection properly;

ProxyBuilder incorrectly handled classes with truly abstract methods;

MSSQLUpdateActionsTranslator could produce SQL code dropping primary key constraint before dropping full-text indexes. This is incorrect - full-text indexing service uses primary keys to identify the rows related to the full-text index data, so this was always leading to the update error.

DatabaseModelComparer incorrectly handled column's collation change - it considered two columns with the same properties but different collations as completely different columns. The data loss should occur in this case, or this could lead to another errors - e.g. an error should occur if the unique constraint was specified for a new column, and old column contained more then one value. This was the most noticeable problem that appeared on almost any execution of Demo_WebTransfers (that normally uses DomainUpdateMode.Perform) after Demo_Books or Demo_Transfers execution.


Version 1.8.1

What's new

Automatic transactions support was seriously improved: new architecture significantly reducing the number of inner transactions in the applications and consequently increasing the performance - each inner transaction requires delayed updates to be flushed before its beginning and completion.

New improvements allows to never use TransactionMode.NewTransactionRequired - you can use TransactionMode.TransactionRequired option except, but in exchange you should property use:

TransactionMode.Unsafe option, or

Write safe exception handlers in your transactional objects. You can find more information about this in the SessionBoundObject.SafeXXX methods and TransactionController class descriptions (look DataObjects.NET CHM Help).

Note: it's better to replace all existing TransactionMode.NewTransactionRequired options in your applications to TransactionMode.TransactionRequired. Please, pay attention to the new TransactionMode.Unsafe option (look DataObjects.NET CHM Help).

Note: TransactionMode is now marked by [Flags] attribute;

Transaction.Lock() & Transaction.Unlock(...) methods were added;

TransactionController (helper type) was introduced, ProxyBuilder now uses this type in the generated proxy code. TransactionController solves three primary tasks:

It simplifies proxy code;

It helps to code safe exception handlers;

It automatically locks\unlocks the underlying transactions making the code safer (so currently only the code that has a reference to the corresponding TransactionController can commit the transaction that was initiated by it).

Note: all mentioned changes have serious effect on inner transaction creation behavior.

We introduced two new base types (primarily to make the DataObjects.NET architecture more clear):

SessionBoundObject: almost all objects that can exists only within the Session are descendants of this type. The only exception is TransactionController - it is Object descendant (this makes impossible to marshal the instances of this type between different application domains);

TransactionalObject (SessionBoundObject descendant): it is the base class for all types requiring DataObjects.NET-generated runtime proxy to function properly. Currently there are two well-known descendants of this type - DataObject and DataService.

DataObjectsCollectionBase.PreLoad() and QueryBase.PreLoad() methods were added. These methods pre-fetches instantiation data allowing to instantiate preloaded objects without any additional queries further (of course, if the data will still be cached and valid on the moment of actual instantiation - e.g. the data can be invalidated on the rollback of transaction where it was fetched).

Use of Savepoints now can be disallowed through SessionSecurityOptions.


DataObjectCollectionBase.GetContainedIDs() was renamed to GetIDs();

ObjectModel.IReferenceHolderField.GetContainedIDs() was renamed to GetIDs(), all it's implementers was correspondingly modified;

Session.CreateObject(...) behavior was modified: now it persists the newly created instance immediately after calling its OnCreate(...) method (without delaying insert operation). We found this action is strongly required to comply with the rules of the DataObjects.NET transactional environment. So when the performance is critical, it's a good idea to use OnCreate(...) methods with as complete set of initialization parameters, as possible (to reduce the number of queries).

Overview section of the DataObjects.NET Manual was slightly updated.

FAQ & Readme were slightly updated.


QueryBase.Execute(QueryOptions options) didn't work properly when options differed from the QueryBase.Option property;

Serious error in the Query translation engine: in some cases Query was producing improper join condition for {CollectionProperty.item.Property} - type expressions.


Version 1.7.1

What's new

Delayed updates: this is new feature of DataObjects.NET - now almost all types of updates are delayed by default and flushed as late as it's possible. Late update sequence is normally executed via much less number of queries. This feature is almost equivalent to using BeginUpdate()\EndUpdate() blocks in the earlier versions of DataObjects.NET, but always whenever it's possible. On most of our update - related tests use of this feature reduces execution time by 20-40%. Now DataObjects.NET delays all possible updates, but flushes all of them on:

Beginning\Committing\Rolling back a transaction (including inner transactions). So as result, invocation of any method that requires a new transaction (e.g. DataObjectCollection.Clear()) leads to flushing of all delayed updates;

Execution of any Query or SqlQuery (to ensure that information in the database is synchronized with in-memory objects prior to the query execution);

Removal of any instance - again to synchronize the database content prior to execution of reference removal process;

Session.Persist() invocation (after calling this method the database becomes completely synchronized with in-memory objects);

Also the updates that related to a particular instance can be flushed on:

Attempt to read the ID or VersionID properties of the newly created instance (i.e. instance that was created, but not yet persisted to the database);

Attempt to set a reference property that has paired collection (to ensure that this collection will reflect the changes further);

DataObject.Persist() invocation (Session.Persist() do the same, but for all instances that contain delayed updates);

There are some other situations than delayed updates related to a particular instance will be flushed.

Additional notes:

Look SessionSecurityOptions.AllowChangeDelayUpdatesOption;

All updates (of the current instance) are delayed during OnCreate(...) method execution, even if Session.DelayUpdates is set to false. This eliminates possible additional updates during the instance creation;

Any updates are delayed during deserialization of the instance, even if Session.DelayUpdates is set to false.

You can increase the performance by rearranging the parts of your code - i.e. it's better to group the statements that don't lead to flushing of delayed updates.

DataObject.BeginUpdate() and DataObject.EndUpdate() methods are now protected (formerly they were public). So it's still possible to use this behavior internally in your persistent classes, e.g. to delay the updates when even Session.DelayUpdates is set to false.  But in all other cases this option brings nothing additional.

You should use Session.Persist() and DataObject.Persist() methods e.g. when:

You're going to execute a custom query via Session.RealConnection() - to ensure that database is synchronized with in-memory objects;

Some long-time external operation should take place, so it's better to perform an update prior to it.

Note: if you don't use Session.RealConnection and other "real" objects, you normally shouldn't even think about Persist() invocation - as is was mentioned earlier, DataObjects.NET handles this task completely automatically as part of completely transparent persistence that it provides.

Now there is only one QueryResult type, but it supports 4 types of internal representation (look QueryResult.Options and new QueryOptions). In the earlier versions there were two types of QueryResult - QueryResult and QueryResultLOD (its descendant), now latter's behavior is completely reproduced with use of QueryOptions.HoldInMemory option. New implementation of result set allows to:

Choose between faster object instantiation (all data required to instantiate objects is fetched during a single query, but in this case much more data is transferred and stored before actual instantiation) and low memory consumption + faster query execution (only IDs of instances are transferred during the query execution and only list of these IDs is stored temporarily - so you can use this type of the result set when only a small part of it should be processed). See QueryOptions.LoadOnDemand option;

Choose between what to store internally: a real references to DataObject instances (in this case these objects couldn't be collected during the garbage collection) or only IDs of objects (in this case any contained objects can be collected during GC - use this type of the result set when it is large, e.g. when it contains more then 10000 objects);

QueryResult objects can be created not only by Query.Execute(...) invocation, but manually (e.g. by new operator, or Session.CreateQueryResult(...) methods. So you can use QueryResult anywhere when it's desirable to temporarily store a set of persistent objects.

Content of any QueryResult object can be modified in the runtime - e.g. you can add new objects to it. Also any QueryResult can be locked (see Lock() method description).

QueryResult can be created from array of IDs of persistent objects, and vice versa it can return an array of object IDs it contains. This feature greatly helps than it's required to implement result set caching - look Search.aspx.cs of the DoPetShop sample for real-life example of use of this feature. Note that internally any QueryResult normally stores more then such an array (to speed-up object instantiation).

Improved caching: now DataObjects.NET caches not only instances of persistent objects, but also instantiation data collected during Query\SqlQuery execution! Consider the following situation:

You executed a query (QueryOptions.LoadOnDemand should be turned off - or it would be no data to cache), that returned a result set with some persistent object, e.g. with ID=1205 (note, that persistent object wasn't instantiated after this action - because you didn't try to access it);

Then you e.g. processed this result set, but skipped mentioned object (so it is still not instantiated), or even forgot about the whole result set;

And after that you made an attempt to access mentioned object, but not through this result set. E.g. you executed myObject = session[1205], or passed through a reference held by another persistent object (by using e.g. someObject.Fiends[0].Parent construction, or by accessing this instance through another QueryResult created with QueryOptions.LoadOnDemand option - such result sets doesn't contain any instantiation data). In this case DataObjects.NET will make an attempt to reuse cached instantiation data fetched by the first mentioned query! Exactly, it's quite probable that persistent object with ID=1205 will be created without any additional queries - if:

It's instantiation data is still cached (so it wasn't removed during possible garbage collections);

This data wasn't created in the subtransaction, that was rolled back (the same about savepoints);

This data was created in the current outermost transaction, otherwise fast version check query will be performed;

Note: you can use this behavior to pre-cache objects that should be processed further. Consider the following situation: you should process very large set of persistent instances, so it's even impossible to hold all their instantiation data in memory. So you can obtain a result set with all these instances only with QueryOption.LoadOnDemand option, and use additional queries with condition like "ID in (id1, id2, ... idN)" (but without QueryOption.LoadOnDemand) to pre-cache sets of objects from the main result set that are planned to be processed during the next step.


DataObject.Modified property was renamed to Changed (the value of this property indicates if a particular instance contains delayed updates);

SessionSecurityOptions.AllowChangeAutoDisconnectSettings was renamed to SessionSecurityOptions.AllowChangeAutoDisconnectOption;

All samples are updated to support recent changes (primarily delayed updates);

Search.aspx.cs in DoPetShop now uses new QueryResult behavior to cache search results;

DataObjects.NET Manual, Readme & FAQ were updated; Revision History was converted to PDF.


Oracle driver could throw an exception on attempt to insert\update zero-length string;

NativeOracle driver could throw an exception on attempt to insert\update zero-length binary field;

QueryBase.Execute didn't reset QueryOptions.Count flag (so if it was set manually, this method would throw an exception);

DoPetShop .aspx/.ascx page code was fixed - now all pages are correctly displayed in the Visual Studio .NET designer;

It was possible to omit removal of [Contained] items in the paired (marked by the [PairTo] attribute) collection on removal of the instance with such a collection;

Session.Item[long ID] didn't require new or existing automatic transaction. So if this method was called with an ID of non-cached instance, and not within BeginTransaction()\EndTransaction() block, and with Session.AutoDisconnect option, an exception was thrown (connection is closed).


Version 1.6.4

This version primarily resolves Windows Server 2003 - related problems.


Now you can use PairToAttribute instead of Symmetric attribute - use [PairTo(typeof([CurrentType]),"[CurrentProperty]")] form in this case. We added this opportunity to simply increase the genericity;

DatabaseSetupWizard supports Windows Server 2003 - now it is able to create additional IIS_WPG login on Microsoft SQL Server mapped to IIS_WPG Windows group;

Documentation updates:

Running DataObjects.NET Samples section was updated (now it covers Windows Server 2003 - related tasks);

Tutorials section was added - currently there is only one tutorial (References and Collections).


Version 1.6.2

What's new

!!! License agreement was changed: we reduced evaluation period from 120 days to 45 days;

We added new DoPetShop Remoting Client sample - this is a GUI application that uses DoPetShop SearchService;

SAP DB Driver now accepts Version parameter. Look description of SAPDBDriver class in the DataObjects.NET.chm;

Native Oracle Driver now accepts DBA parameter. Look description of OracleDriver class in the DataObjects.NET.chm.


Version 1.6.1

What's new

!!! License agreement was slightly changed;

Price of the DataObjects.NET Single Developer License was increased, now it costs $495;

We added 3 DataObjects.NET License Packs: for 3 ($1295), 5 ($1995) and 10 ($2995) developers;

Trial version limitations are changed:

Now Trial version supports DateTime and Decimal field types;

You can evaluate Trial version for 120-days period, but any Trial version still required to be updated to the newer version after some date (we normally choose this date as release date + one-two months period);

You can use up to 15 custom persistent types (DataObject descendants) in a single Domain;

You can use up to 5 services (DataService descendants) in a single Domain;

Up to 30 tables can be used by a single Domain;

New and most interesting sample was added: DoPetShop. This is a DataObjects.NET-based clone of the famous .NET Pet Shop. Read more about this sample in the DataObjects.NET Manual.

We introduced DataServices:

DataServices are descendants of the DataService class;

DataServices should be registered in the Domain by RegisterServices\RegisterService invocation;

DataService instances can't store any persistent data itself;

Session.CreateService(...) or Session.GetService(...) should be called to get\create a DataService instance within a Session. So each DataService instance is bound to some Session (like DataObjects);

For each registered DataService instance a proxy class is generated by DataObjects.NET. These proxy classes handle automatic transactions during the instance method invocation (again like with DataObjects).

You should use DataServices to implement common services (classes that don't contain persistent data itself, but manipulate with), e.g. LoggingService. It should be much easier to use this conception because of DataServices' automatic transactions support.

OnInitInstance(...) event was removed, but OnCreate(...) method (with possible overloads) is introduced. So now you can write "typed" constructors with DataObjects.NET. Session.CreateObject(...) now invokes correct type of OnCreate(...) method (determined by type of passed arguments);

Domain.DebugInfoOutputFolder property was added - it allows to:

Debug the proxy assembly (e.g. step into it) built by DataObjects.NET - its C# source code will be written to this folder, proxy assembly will be compiled with the debug option;

View dumps of all domain models (object model, database model and extracted database model), database schema update SQL code - corresponding files will be written to this folder;

Note: you should give write permission to the Domain.DebugInfoOutputFolder for ASPNET account to use this property within the ASP.NET application.

Serializer.AssemblyFormat property was added.


All documentation was updated, FAQ section is now located in the separate file (FAQ.pdf);

Samples Database Setup Wizard now allows to create DoPetShop database;

Session.CreateDataObject(...) was renamed to Session.CreateObject(...) - we decided to slightly shorten well-understandable name;

Serializer.TypeStyle was renamed to Serializer.TypeFormat;

All samples were updated (to support mentioned changes).


QueryBase.ExecuteCount() didn't work when OrderBy condition was specified;

Serious Query translation error was fixed: the translation engine implemented in the Query class used "Table as tableAlias" construction, but SAP DB and Oracle support "Table tableAlias" construction (without "as" keyword);

It was impossible to override default case sensitivity of a Culture by specifying CompareOptions explicitly in its constructor;

In the [Indexed("IndexName")] declaration "IndexName" was always ignored (so this declaration worked as simply [Indexed]);

An error in the instance removal algorithm that could lead to illegal number of references displayed by the Count property of a collection that is paired to some reference property of the removed instance;

Serializer.LastOperationInstanceCount could show wrong number of processed instances after the serialization.


Version 1.5.1

What's new

Now it's really simpler to perform queries in DataObjects.NET - query engine was seriously improved: now there are two query classes: SqlQuery (it was formerly called Query) and Query (providing new object-oriented query mode).

Some examples of new query expressions:

1) Select Namespace.Model.Author instances

     where {Name}='Alex';

2) Select Author instances         // Short type name notation

     where {Name-En} like 'Alex%'; // This is still SQL :)

3) Select Author instances

     where {Books.count}=3;        // Counting

4) Select Author instances

     where {Books.item.Authors.count}=3;

5) Select Author instances

     where exists{Books[{Owner}<>{root}]}

     // {root} is current instance in the main query,

     // also {parent} and {this} can be used.

6) Select top 5 Author instances

     with (fastFirst,forUpdate)

     where {Books.Expression[avg(len{Title})]} > @AvgLen;

     // @AvgLen is parameter, now parameter notation for different

     // database drivers is _the same_, even with SqlQuery.

7) Select Animal instances

     where {this."Parent"}<>{this}

     // The way to refer to Animal.Parent property.

8) Select Author instances

     where {Name}>='D'

     textsearch top 5 freetext 'Jungle' // Full-text search

       in {FullTextIndexedObject.FTD}

     order by {FullTextRank}

Note: object query translation engine currently isn't well optimized for in-depth queries.

Now you can use @parameter notation with any database driver (even with SqlQuery). Look QueryParameter and QueryParameterCollection classes;

Two versions of Oracle driver: first uses Microsoft's Oracle Data Provider and second uses Oracle Data Provider for .NET (ODP.NET). Second version is implemented as external driver and loaded only on demand (primarily because it requires ODP.NET to be installed). Currently it's recommended to use first Oracle driver (i.e. use "oracle" protocol in the connection string).


Default value of Domain.IdentifierPrefix was changed from "nds" to "do";

Several changes in database driver specification;

Now private properties are considered as non-persistent by default in the DeclarationMode.PersistentByDefault, you can use [Persistent] attribute to make them persistent in this case;

FullTextIndexedObject was significantly changed;

[Transitive] attribute is renamed to [Symmetric];

InvalidSQLException was renamed to InvalidSqlException;

All samples are updated (to support Oracle and new Query type);

Demo_WebTransfers code is updated (now it uses DataContext);

Some small changes (e.g. we decided to make some additional classes sealed).


A bug in the deserialization layer that could appear in the DeserializationOptions.EnableOverwrite mode. It could "overwrite" an instance that belongs to the deserialization graph (if new ID of this instance is equal to the ID of another instance in the deserialization graph that isn't deserialized yet);

It was possible to make two DataObjectCollection fields having [PairTo] attributes pointing to the same field;

It was possible to make two DataObjectCollection fields having [PairTo] attributes pointing to each other;

All views were always recreated in the DomainUpdateMode.Perform. Now this action takes place only when necessary.

Collection that is paired to some property didn't immediately reflect the change of the property;

It was impossible to use DataObjectCollection descendants because of bug in DataObjectCollectionField code;

In some cases FastLoadData value wasn't fetched during the population of a query result.


Version 1.3.2

What's new

One new property (Permissions) is added to DataObject class. Currently you shouldn't use it - it is added only because this version is built from a branch with partially implemented security system;

Now it's possible to customize the serialization of DataObject instances (look OnSerialize, OnDeserialize);

SerializationOptions.AlwaysUseReferences option added.


A combination of property update and immediate rollback of the inner transaction could lead to possibility to get the updated value of the property immediately after rollback.


Version 1.3.1

What's new

Now all abstract\virtual properties of persistent classes (DataObject descendants) are persistent by default (earlier it was necessary to apply [Persistent] attribute to specify the same). To mark some property as non-persistent you should apply [NonPersistent] attribute to it. Also you can use [DeclarationMode] attribute (apply it to class) to select preferred declaration mode (new or old).



Trial version will be functional until November 01, 2003.


Fixes in Microsoft SQL Server driver:

Invalid SQL code is generated for Decimal fields during database update (this bug appeared since version 1.2).


Version 1.3

What's new

Now DataObjects.NET completely supports serialization of DataObject instances - look DataObjects.NET.Serialization.Serializer class.

[NonSerializable] attribute was added. It has the same effect as [NonSerialized] attribute (in the .NET Framework), but can be applied to [Persistent] properties;

Samples Database Setup Wizard was added;

DataObject.DefaultCulture property was removed (primarily because it was rather confusing feature - to use\browse several instances with different DefaultCulture values). Now you should use Session.Culture instead of it.


DataObjects.NET Manual & Readme:

A lot of grammar errors are fixed :(. Our English isn't so good as our programming skills (as we trust)...

New features are briefly described.

DataObjects.NET CHM Help:

Documentation on Serializer and related classes added;

Some grammar errors are fixed. Actually there are still plenty of them...

Other minor updates.


LoadAll() method incorrectly fills the table of properties required to load.


Version 1.2.6

What's new

All attributes were moved to the DataObjects.NET.Attributes namespace;

Isolation level can now be specified for any Transaction (including inner transactions);

[Transactional] attribute now supports isolation level settings.


DataObjects.NET CHM Help:

Values of enum fields was added to the documentation;

Other minor updates.


One more bug in the DataObject.Reload() method.


Version 1.2.5

What's new

Distributed transactions are now supported. Currently only by the Microsoft SQL Server driver - SAP DB driver doesn't support this feature because of SAP DB ODBC driver limitations, but the Oracle driver will. Look Session.EnlistDistributedTransaction(...) method.




Version 1.2.1

What's new


Distributed transactions support code (currently it isn't finished, so distributed transactions are disabled by all database drivers yet).


Session.AutoConnect replaces with the Session.AutoDisconnect;

SessionSecurityOptions are slightly changed;

TransactionCanBeReprocessedException added, it is handled in the same way as the DeadlockException before. Now DeadlockException is its descendant.

InstanceVersionChangedException added (a descendant of the TransactionCanBeReprocessedException).

DatabaseModel.ExtractedInfo class is slightly changed.

DataObjects.NET.Database.Persister.LockDataObject definition is slightly changed;

SAP DB driver:

Speed-up optimization (set of calls were removed, 1 simple method was expanded inline).


Bug in the DataObject.Reload() fast version check code (this code was introduced in the v1.2) allowing to improperly pass the version check. The following conditions should be satisfied to meet this bug:

Session A should begin an outermost transaction, fetch the instance with ID=id1, modify one of its property (e.g. set it to the ValueA) and rollback a transaction;

After that Session B should do the same, but setting another value to the same property (e.g. ValueB) and finally committing a transaction;

Session A should begin a new transaction and get the value of the modified property (of the same instance). If the instance is still in the cache of the Session A, instance data should be invalidated (this should lead to refetching of the required property). But because of the mentioned bug instance will pass the version check and no refetching will occur (so result of the get operation will be ValueA rather then ValueB).

It's rather difficult to occasionally meet this bug - described situation can occur only under highly concurrent operations on the limited set of instances. It was enough difficult to locate this problem (it was discovered on one of our stress tests).

Fixes in Microsoft SQL Server driver:

MSSQLDriver.CreateConnection now manually specifies that created IDbConnection shouldn't be automatically enlisted in the current distributed transaction;

Fixes in SAP DB driver:

SAPDBPersister.LockDataObject(...) produced invalid SQL code;

SAPDBPersister: instance update\delete code contained incorrect version check condition. The effect: possibility to update\delete an instance that was concurrently updated by another transaction on the read committed isolation level;

OdbcException with the NativeError code 500 (lock timeout) is now also converted to the DeadlockException;

Unique indexes were used except of the primary keys.


Version 1.2

What's new

Automatic transactions (look [Transactional] attribute);

Automatic method call\property access reprocessing on DeadlockException (look Session.ReprocessingDelay, Session.ReprocessingAttemptsCount);

Nested transactions;

Basic security options for Domain & Session (see Session.SecurityOptions and Domain.SecurityOptions, possibly you should change values of this options to make your existing application work);

Automatic opening\closing connection on beginning\ending of outermost transaction (look Session.AutoConnect property);

ConnectionTimeout parameter support (both in MS SQL & SAP DB drivers);

Now it's impossible to switch off version checking for Session (Session.CheckVersions property was removed);

Proxy builder extensions:

[NonOverridable] attribute;

[TypeReference] attribute allows to resolve problems with "unreferenced assemblies";

[ProxyAttribute] attribute and support of attribute copying (in proxy class);

Automatic transactions support (generation of corresponding code).

Recyclable properties - DataObject properties, that shouldn't be recreated during instance invalidation (look DataObject.Reload(...) method), but their content should be changed. E.g. DataObjectCollection is the type that supports recycling;

Oracle driver classes (please, don't try to use current implementation, this is not even beta).


Improved DataObject.Reload() code - now it first compares versions of stored and in-memory instances, and if they are the same, it simply exits;


All samples are updated (to support automatic transactions and other new features);

Demo_Transfers now operates in automatic transactions mode, also it is configured to handle deadlocks transparently. Now it's almost impossible to see DeadlockException in this demo, but you can try to turn deadlock handling off to see that actually deadlocks can take place;

DataObjects.NET Manual:

Automatic transactions description added;

Frequently Asked Questions section;

Running Samples section;

Other updates;

DataObjects.NET CHM Help:

New classes described;

Fixed previous .CHM Help version error - absence of external class\method\property descriptions;

Other minor updates;

DataObjects.NET Readme.


Now Domain.NamingMode affects on view names too;

Fixes in Microsoft SQL Server driver:

QueryOptions translation could produce invalid options combination (not critical);

Fixed MSSQLInfo.IndexedStringPartLength (not critical);

Fixes in SAP DB driver:

Isolation Level was always ReadCommitted (SAP DB ODBC driver doesn't understand isolation level settings through ODBC API, now DataObjects.NET SAP DB Driver sets correct isolation level by additional query);

QueryOptions translation wasn't correct;

SAPDBUpdateActionTranslator.UnregisterOldTypes() was producing bad SQL code ( ... "ID" in ("1","2",...));

Savepoints list isn't cleared on the beginning of new transaction;

Savepoints list stays unchanged if exception occurs on rollback to savepoint (actually on rollback of inner transaction);

Faster Savepoints implementation (fixes in "rollback to savepoint" code);

Invalid connection string is produced if User wasn't specified in connection URL.


Version 1.1

What's new

This version supports only .NET Framework 1.1, version for .NET Framework 1.0 is available only by request now.

SAP DB support is now out of beta stage;

ASP.NET sample;

Domain.ConfigureInstanceLifetime(...) method added (useful when you marshaling Domain instances via .NET Remoting);

Default lease lifetime for the Domain instances is now infinite. Before it was same as of any other MarshalByRef instance, or 5 minutes by default.  It was possible to override this behavior (by using LifetimeServices or sponsorship), now it is even more simple.

System32.Single type is now supported;

DataObjects.NET Manual updates:

Added Demo_WebTransfers description;

Added Frequently Asked Questions section;

Tips and SAP DB driver section are updated;

Other minor updates\fixes.

DataObjects.NET CHM Help updates:

Several samples added;

Other minor updates\fixes.

DataObjects.NET Readme updates:

Minor updates\fixes.


Index comparer (in database schema update layer) incorrectly compared non-fulltext index properties, updates were skipped for these indexes if this error took place;

SysType comparer sometimes assigned illegal (already used) type identifiers. This error appeared only in DomainUpdateMode.Perform and DomainUpdateMode.PerformSafe update modes;

ProxyBuilder sometimes didn't put appropriate reference to DataObjects.NET assembly. In this case exception during Domain.Build was thrown making impossible to use the domain. This error primarily occurred within ASP.NET applications. One way to fix it was to put DataObjects.NET.dll to GAC (now this is not required);

Fixes in MS SQL driver:

Records could be lost if table column type is changed during update (even to compatible type).

Fixes in SAP DB driver (all are very important):

Records could be lost if table column type is changed during update (even to compatible type);

Schema extractor extracts SqlType.Double as SqlType.Float;

Schema extractor incorrectly extracts Nullable & Autoincrement values;

Schema comparer incorrectly compares columns with SAP DB (SAP DB doesn't support collations, but it considers it does);

Because of two upper mistakes DomainUpdateMode.Perform was almost always working as DomainUpdateMode.Rebuild;

FlashFastLoadData produces incorrect SQL code for SAP DB - with SAP DB it's impossible to update FastLoadData LONG BYTE column to x'' (empty byte sequence), so now it updates this column to NULL with SAP DB.


Version 1.1b

What's new

SAP DB driver;


Driver.Info, Domain.DriverInfo, Session.DriverInfo properties.


Several changes in Database Driver Layer;

Default size of VarChar, AnsiVarChar - type fields;

Documentation (DataObjects.NET Manual, Readme, CHM Help).


Error in Enum support code (illegal conversion);

Wrong default value format for DateTime;

ObjectModelBuilder type check sometime produced unexpected results;

Culture to collation conversion algorithm couldn't determine collation for de-CH and set of other cultures;

Other minor updates.


Version 1.02


All exceptions were moved to DataObjects.NET.Exceptions namespace;

Other minor updates.


SysInfoManager used wrong SysInfo table name in method, that was currently unused.


Version 1.01


Redundant space in FastLoadData.


License Agreement (EULA) was significantly changed;

.NET Remoting layer;


Configuration files were added for .NET Framework 1.0;

Minor fixes and changes;

Documentation (DataObjects.NET Manual).


Version 1.0

First public release.