Domains
Domains overview
Domain is the primary storage access point. It is responsible for:
Building and maintaining storage-wide information, such as persistent model (like reflection in .NET, but specialized for persistent types), database model (tables, indexes and so on), mappings between them CLR types & properties and database entities (tables, columns, etc).
Validating and upgrading the database schema.
Creating
Sessionobjects, you can consider it is aSessionfactory as well.Note
Domainobjects can be used concurrently, as well as any other read-only content available from it (e.g.Domain.ModelorDomain.ExtractedSchema).
To create a domain, you must create DomainConfiguration first. And
there are several ways of doing this:
You can create it manually in code
Load it from App.config section
Finally, you can load it from App.config and modify it
In our example we’ll use the 3rd way:
// Loading the configiration from App.config section
var config = DomainConfiguration.Load("Default");
// Modifying it by registering all the types from specified assembly
config.Types.Register(typeof(MyEntity).Assembly);
// And finally building the domain
var domain = Domain.Build(config);
Now we have the Domain object. But to start working with persistent
entities, we need a Session instance.
Configuring domain
To configure and build a Domain, you can use DomainConfiguration
class. It contains a set of options that could be used to customize
DataObjects.Net domain-level behavior.
Connection to database
DataObjects.Net supports two alternative ways of providing connection information:
Using connection string name syntax. It allows to specify standard connection string for underlying ADO.NET provider. Using connection string is the recommended approach.
Using connection URL syntax. Its main advantage is unification (the same syntax for all supported databases). Connection URLs are similar to those used in DataObjects.Net 3.x.
Connection string syntax
For specifying connection information DataObjects.Net provides support
for standard ADO.NET connection string syntax. You can pass provider
name and connection string to DomainConfiguration constructor:
var config = new DomainConfiguration("sqlserver",
"Data Source=localhost; Initial Catalog=Tests; " +
"Integrated Security=True; MultipleActiveResultSets=true;");
Possible provider names are sqlserver (used for connecting to
Windows Asure Database as well), oracle, postgresql, mysql,
firebird and sqlite. Their canonical names can be found in
Xtensive.Orm.WellKnown.Provider class.
You can use connection strings in Domain configuration sections of App.config as well:
<domain
name="Default"
provider="sqlserver"
connectionString="Data Source=localhost; Initial Catalog=MyDatabase;Integrated Security=True;"
upgradeMode="Recreate" />
We recommend to use MultipleActiveResultTests parameter in
connection string. Since DataObjects.Net supports on-demand
materialization, this option allows it to deal with very large result
sets. When this option is turned off, DO4 loads every result set
completely. If connection URL is used instead of connection string, it
is automatically added to underlying connection string.
ConnectionStrings.com provides many connection string examples for various ADO.NET providers.
Connection URL syntax
Connection URL can be passed to DomainConfiguration constructor or
by assigning appropriate value to ConnectionUrl property:
var domainConfig = new DomainConfiguration("sqlserver://localhost/MyDatabase");
Alternatively you can specify connection URL in App.config section:
<configuration>
<configSections>
<section name="Xtensive.Orm" type="Xtensive.Orm.Configuration.Elements.ConfigurationSection, Xtensive.Orm" />
</configSections>
<Xtensive.Orm>
<domains>
<domain name="Default" connectionUrl="sqlserver://localhost/MyDatabase" />
</domains>
</Xtensive.Orm>
</configuration>
Any connection URL has the following structure:
protocol://user:password@server/database?parameter=value¶meter=value
Protocol is identical to provider name when using connection string. See previous section for details. Some parts of connection URL are optional, actual values and parameters may vary with each RDBMS. Any additional parameters are passed to underlying ADO.NET provider as is.
Microsoft SQL Server
sqlserver://localhost/Tests— connecting to database ‘Tests’ on a local machine with Windows authentication.sqlserver://localhost\SQLExpress/WebSite— connecting to database ‘WebSite’ on a local machine with Windows authentication and non-default instance name ‘SQLExpress’.sqlserver://iddqd:idfka@dbserver/Sales— connecting to database ‘Sales’ on a remote machine ‘dbserver’ with SQL Server authentication.
Azure SQL Database
sqlserver://login:password@server.database.windows.net/database— actual connection parameters could be taken from admin panel
PostgreSQL
postgresql://user:password@dbserver/tests— connecting to database ‘tests’ on server ‘dbserver’ as specified ‘user’ with specified ‘password’.postgresql://user:password@dbserver/tests?Pooling=True&MinPoolSize=1&MaxPoolSize=5— connecting to database ‘tests’ on server ‘dbserver’ as specified ‘user’ with specified ‘password’. Connection pooling is enabled.
Oracle
oracle://user:password@dbserver/tests– — connecting to database with service name ‘TESTS’ on server ‘dbserver’ as specified ‘user’ with specified ‘password’.oracle://user:password@/sales— connecting to database SALES that is defined in TNSNAMES.ORA file.
Firebird
firebird://john:qqq@localhost/tests?Dialect=3&Connection lifetime=15&Pooling=true&MinPoolSize=0&MaxPoolSize=50&Packet Size=8192&ServerType=0— connecting to database ‘tests’ as user ‘john’ with password ‘qqq’. Line breaks are added for formatting purposes.
SQLite
sqlite:///.\Tests.db3— using database file Tests.db3 in current directory.
Default schema
By default DataObjects.Net maps all the entities to the default schema
for the user specified in connection URL / string (authenticated user).
If another schema must be used, you can specify it in
DomainConfiguration.DefaultSchema or defaultScema attribute of
domain element in App.config section.
Persistent types
Then you must register persistent types that will be used to build
persistent model. Use Types collection and its Register method
overloads to register single type, namespace or whole assembly. It is
recommended to declare all persistent classes in separate namespace,
e.g. MyCompany.MyProduct.Model and register all classes in this
namespace.
domainConfig.Types.Register(
typeof (Person).Assembly, typeof (Person).Namespace);
<domain
name="Default"
provider="sqlserver"
connectionString="Data Source=localhost; Initial Catalog=MyDatabase; Integrated Security=True;"
upgradeMode="Recreate">
<types>
<add assembly="MyCompany.MyProduct.Model" />
</types>
</domain>
Persistent model can be also separated into several assemblies. In this case all assemblies that contain persistent model should be registered in domain types.
Upgrade mode
When domain is being built it analyzes existing database structure, and
tries to upgrade it to actual model version. UpgradeMode property of
DomainUpgradeMode type specifies how this upgrade should be
performed. There are several available options:
Validate— Domain will check whether database schema is compatible with persistent model, anyway it will not be modified. If schema is incompatible, exception will be thrown.Skip— No checks on database schema are performed. It is assumed to be compatible with current domain model.Recreate— Database schema will be completely recreated, all existing data will be removed.Perform— Storage upgrade will be performed. All missing database structures (columns, tables) will be added, excess ones will be removed. See database schema upgrade chapter for further details.PerformSafely– The same asPerformmode, but any destructive operations (column or table removals, column type changes) require explicit declaration. If they are not explicitly declares exception is thrown before modifying database schema.LegacyValidateandLegacySkip— legacy database compatibily mode with semantics similar toValidateandSkiprespectively. See Legacy support section for more information.
Default upgrade mode value is PerformSafely.
domainConfig.UpgradeMode = DomainUpgradeMode.Recreate;
Naming conventions
NamingConvention property contains a set of rules for naming
database structures such as tables, columns, indexes, etc. Several
options are available.
NamingRules specifies underscore substitution for special symbols:
UnderscoreHyphens— replace all hypens with underscore symbol.UnderscoreDots— replace all dots with underscore symbol.Both options could be used.
By default dots and hypens are not underscored.
LetterCasePolicy specifies name transformation:
AsIs— no case transformations. This is default policy.UpperCase— all identifiers are converted to upper case.LowerCase— all identifiers are converted to lower case.
NamespacePolicy specifies namespace substitution for persistent
entities:
Omit— omit namespace from table names. This is default option.AsIs— namespaces are prepended to table names.Hash— short namespace hashes are prepended to table names.Synonymize— namespaces are replaced according toNamespaceSynonymscollection. You can provide your own prefix for each namespace. It would be prepended to table names. If namespace synonym is not specified for a particular namespace full name is used similar toAsIsmode.
Miscellaneous options
BuildInParallel property allows to enable parallel construction of a
Domain. DataObjects.Net tries to minimize time for
Domain.Build() by performing certain operations in separate thread.
This option is enabled by default. If you for some reason don’t want
separate thread to be used you could set this property to false.
ForcedServerVersion property allows to turn compatiblity with a
particular version of database server. By default DataObjects.Net
detects server version at start-up and uses recent features if they are
available.
configuration.ForcedServerVersion = "9.0.0.0";
IncludeSqlInExceptions property allows to control message of
exceptions that are thrown when error occurs when executing SQL query.
By default query that cause the error is included into exception. You
could disable such behavior by setting this property to false.
SchemaSyncExceptionFormat property allows to control message of
exceptions that are thrown when database schema is not compatible with
expect one. Two options are available:
Detailed— all relevant information is included. This is default option.Brief— full schema difference is ommited. This enables behavior of DataObjects.Net 4.4 and earlier.
Loading domain configuration
Domain configuration can be also loaded from application configuration file. To do this you should add DataObjects.Net configuration section in your configuration file. One configuration section can contain several domain configurations, in the following example two domain configurations are declared (“stage” and “production”):
<configSections>
<section
name="Xtensive.Orm"
type="Xtensive.Orm.Configuration.Elements.ConfigurationSection, Xtensive.Orm" />
</configSections>
<Xtensive.Orm>
<domains>
<domain name="stage"
upgradeMode="Recreate"
connectionUrl="sqlserver://localhost/MyStageDatabase">
<types>
<add assembly="MyAssembly" namespace="MyProduct.Model" />
</types>
</domain>
<domain name="production"
upgradeMode="Skip"
connectionUrl="sqlserver://localhost/MyProductionDatabase">
<types>
<add assembly="MyAssembly" namespace="MyProduct.Model" />
</types>
</domain>
</domains>
</Xtensive.Orm>
Domain configuration can be loaded from configuration file with the help
of DomainConfiguration.Load() method:
var domainConfig = DomainConfiguration.Load("MyDomain");
Having that done you may change the configuration loaded setting any properties manually:
var domainConfig = DomainConfiguration.Load("default");
domainConfig.UpgradeMode = DomainUpgradeMode.Recreate;
domainConfig.Types.Register(typeof (Person).Assembly, typeof (Person).Namespace);
Building domain
When domain configuration is ready, we can build domain using
Domain.Build() static method:
var domain = Domain.Build(domainConfig);
During the build process DataObjects.Net makes the following steps:
Builds domain model that includes all types registered in
DomainConfiguration.Typesregistry and additional custom definitions.Builds storage schema based on persistent model.
Extracts actual storage schema from database.
Upgrades database schema according to the
DomainUpgradeModespecified inDomainConfiguration.UpgradeMode.
As a result this method will return built and ready to use Domain
instance. Its configuration is accessible in read-only mode from
Domain.Configuration property.
Domain Events
Domain type exposes 2 events:
EventHandler Disposing
Occurs when Domain is about to be disposed.EventHandler<SessionEventArgs> SessionOpen
Occurs when newSessionis opened and activated.
Usually SessionOpen event is used to subscribe to various
Session events of every newly opened Session instance:
Domain.SessionOpen += (source, args) => {
args.Session.Events.TransactionOpened += TransactionOpened;
args.Session.Events.TransactionCommitting += TransactionCommitting;
...
};