NHibernate Integration
GigaSpaces comes with a built in implementation of Space Persistency APIs for NHibernate. This implementation is an extension of the AbstractExternalDataSource
class. The implementation allows a custom objects persistency using NHibernate mappings.
The NHibernate Space Persistency Implementation
is used both with the Synchronous and the Asynchronous Persistency modes.
The NHibernate External Data Source is provided as a reference implementation under $GS_HOME\Practices\ExternalDataSource\NHibernate
. You must build the plugin before using it by running the build.bat
script.
Configuration
The external data source configuration is done via the embedded space configuration within pu.config
- Add an ExternalDataSource
tag and set the Type
to the class implementing the external data source (in this case - NHibernateExternalDataSource
). For example:
<ProcessingUnit>
<EmbeddedSpaces>
<add Name="space">
<Properties>
<!-- Space properties to enable External Data Source -->
<add Name="cluster-config.cache-loader.external-data-source" Value="true"/>
<add Name="cluster-config.cache-loader.central-data-source" Value="true"/>
</Properties>
<ExternalDataSource Type="GigaSpaces.Practices.ExternalDataSource.NHibernate.NHibernateExternalDataSource">
<Properties>
<!-- NHibernate session factory properties: Config file and Location of HBM files -->
<add Name="nhibernate-config-file" Value="NHibernateCfg\nHibernate.cfg.xml"/>
<add Name="nhibernate-hbm-dir" Value="NHibernateCfg"/>
<!-- NHibernate data source properties, for example initial load chunk size -->
<add name="InitialLoadChunkSize" value="2000"/>
</Properties>
</ExternalDataSource>
</add>
</EmbeddedSpaces>
</ProcessingUnit>
In addition to the Type
, the ExternalDataSource
tag contains properties which are injected at runtime to initialize the actual instance. In this case, the NHibernate Session Factory requires 2 configuration settings: A configuration file and the location of theHBM
files. Additional properties can be set to customize the external data source (for example, InitialLoadChuckSize
).
NHibernate Session Factory Configuration File
NHibernate requires a session factory that creates new sessions over the database for each operation executed on it. This walkthrough demonstrates a simple configuration file for the session factory, over a MySQL database server into a database named dotnetpersistency. These parameters are configured in the Connection
string property.
<?xml version="1.0" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory>
<property name="dialect">NHibernate.Dialect.MySQLDialect</property>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.MySQLDataDriver</property>
<!--Connection String-->
<property name="connection.connection_string">Server=localhost;Database=dotnetpersistency;User ID=root;CharSet=utf8</property>
<!--Disable the writing of all the SQL statements to the console-->
<property name="show_SQL">false</property>
<!--Disabled the validation of your persistent classes, allows using .NET properties and not getters and setters on your fields-->
<property name="use_proxy_validator">false</property>
<!--This will create the tables in the database for your persistent classes according to the mapping file.-->
<![--If the tables are already created this will recreate them and clear the data](../Resources/Static/attachment_files/dotnet/--If the tables are already created this will recreate them and clear the data)-->
<property name="hbm2ddl.auto">create</property>
</session-factory>
</hibernate-configuration>
NHibernate Mapping File
Each persistent class requires a mapping file that defines how to map the object to and from the database. For example, for the following Person
class:
[SpaceClass(Persist = true)]
public class Person
{
[SpaceID, SpaceRouting]
public string Name {get; set;}
public int? Age {get; set;}
}
We can use the following Person.hbm.xml
file:
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Entities" namespace="Entities">
<class name="Entities.Person" table="PERSON">
<id name="Name" column="Name" type="string">
<generator class="assigned"/>
</id>
<property name="Age" />
</class>
</hibernate-mapping>
Make sure your PONO [SpaceId]
is defined on the same property as the NHibernate [Id]
. This is necessary for proper object mapping.
See Modeling Your Data for details about these decorations.
Properties
The Hibernate Space Persistency implementation includes the following properties:
Property | Description | Default |
---|---|---|
EnumeratorLoadFetchSize | Sets the fetch size that will be used when working with scrollable results. | 10,000 |
InitialLoadChunkSize | By default, the initial load process will chunk large tables and will iterate over the table (entity) per chunk (concurrently). This setting allows to control the chunk size to split the table by. Batching can be disabled by setting -1 The InitialLoadChunkSize property allows you to have multiple threads loading data from the same table into the space - each thread loading different rows from the same table. Having the InitialLoadChunkSize as 100,000 will break a 1 million rows table into ten chunks. All the chunks, from all the tables, are processes by the amount of InitialLoadThreadPoolSize configured. |
100,000 |
InitialLoadThreadPoolSize | The initial load operation uses the ConcurrentMultiDataIterator . This property allows to control the thread pool size of the concurrent multi data iterator.Note, this usually will map one to one to the number of open connections / cursors against the database. |
10 |
PerformOrderById | When performing initial load, this flag indicates if the generated query will order to results by the id. | false |
UseMerge | If set to true, will use Hibernate merge to perform the create/update, and will merge before calling delete. This might be required for complex mappings (depends on Hibernate) at the expense of slower performance. |
false |
Tuning the EnumeratorLoadFetchSize
, InitialLoadChunkSize
, InitialLoadThreadPoolSize
and PerformOrderById
will allow you to control the initial load time.
See example below:
<ProcessingUnit>
<EmbeddedSpaces>
<add Name="space">
<Properties>
<!-- Space properties to enable External Data Source -->
<add Name="cluster-config.cache-loader.external-data-source" Value="true"/>
<add Name="cluster-config.cache-loader.central-data-source" Value="true"/>
</Properties>
<ExternalDataSource Type="GigaSpaces.Practices.ExternalDataSource.NHibernate.NHibernateExternalDataSource">
<Properties>
<!-- NHibernate session factory properties: Config file and Location of HBM files -->
<add Name="nhibernate-config-file" Value="NHibernateCfg\nHibernate.cfg.xml"/>
<add Name="nhibernate-hbm-dir" Value="NHibernateCfg"/>
<!-- NHibernate data source properties, for example initial load chunk size -->
<add name="EnumeratorLoadFetchSize" value="100"/>
<add name="InitialLoadChunkSize" value="2000"/>
<add name="InitialLoadThreadPoolSize" value="10"/>
<add name="PerformOrderById" value="true"/>
<add name="UseMerge" value="true"/>
</Properties>
</ExternalDataSource>
</add>
</EmbeddedSpaces>
</ProcessingUnit>