Skip to content

Entity database persistence

xhafan edited this page Nov 30, 2018 · 20 revisions

To persist an entity, for example a Ship entity:

public class Ship : Entity, IAggregateRoot
{
    protected Ship() { } // parameterless constructor needed by nhibernate 
                         // to be able to instantiate the entity when loaded from database

    public Ship(string name, decimal tonnage)
    {
        Name = name;
        Tonnage = tonnage;
    }

    public virtual string Name { get; protected set; } // virtual modifier needed by nhibernate 
                                                       // - https://stackoverflow.com/a/848116/379279
    public virtual decimal Tonnage { get; protected set; } // protected modifier needed by nhibernate 
}

into a database, follow these steps:

  1. Add CoreDdd.Nhibernate package into the project.
  2. Create a new NHibernate configurator class derived from BaseNhibernateConfigurator to configure NHibernate and to let it know where to look for entities for persistence:
public class CoreDddSampleNhibernateConfigurator : BaseNhibernateConfigurator
{
    protected override Assembly[] GetAssembliesToMap()
    {
        return new[] { typeof(Ship).Assembly };
    }
}
  1. Add a new file hibernate.cfg.xml into the project to configure which database to persist the entities into.

SQLite example:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>

    <property name="connection.connection_string">Data Source=CoreDddSampleConsoleApp.db</property>
    <property name="dialect">NHibernate.Dialect.SQLiteDialect</property>
    <property name="connection.driver_class">NHibernate.Driver.SQLite20Driver</property>
    <property name="connection.release_mode">on_close</property>

    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="show_sql">false</property>
    <property name="proxyfactory.factory_class">NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate</property>
    <property name="transaction.use_connection_on_system_prepare">false</property> <!-- set transaction.use_connection_on_system_prepare to 'false' when using .NET 4.6.1+ or .NET Standard 2.0+, NHibernate 5.1.0+, more info here https://github.com/npgsql/npgsql/issues/1985#issuecomment-397266128 ; remove this line for previous NHibernate versions -->

  </session-factory>
</hibernate-configuration>

SQL server example:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>

    <property name="connection.connection_string">Server=<server name>; User=<user name>;Password=<password>;Initial Catalog=CoreDddSampleConsoleApp;</property>
    <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>

    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="show_sql">false</property>
    <property name="proxyfactory.factory_class">NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate</property>
    <property name="transaction.use_connection_on_system_prepare">false</property> <!-- set transaction.use_connection_on_system_prepare to 'false' when using .NET 4.6.1+ or .NET Standard 2.0+, NHibernate 5.1.0+, more info here https://github.com/npgsql/npgsql/issues/1985#issuecomment-397266128 ; remove this line for previous NHibernate versions -->

  </session-factory>
</hibernate-configuration>

PostgreSQL example:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>

    <property name="connection.connection_string">Server=<server name>;Port=5432;Database=CoreDddSampleConsoleApp;User Id=<user name>;Password=<password>;Enlist=true</property>
    <property name="dialect">NHibernate.Dialect.PostgreSQL82Dialect</property>
    <property name="connection.driver_class">NHibernate.Driver.NpgsqlDriver</property>

    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="show_sql">false</property>
    <property name="proxyfactory.factory_class">NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate</property>
    <property name="transaction.use_connection_on_system_prepare">false</property> <!-- set transaction.use_connection_on_system_prepare to 'false' when using .NET 4.6.1+ or .NET Standard 2.0+, NHibernate 5.1.0+, more info here https://github.com/npgsql/npgsql/issues/1985#issuecomment-397266128 ; remove this line for previous NHibernate versions -->

  </session-factory>
</hibernate-configuration>

In hibernate.cfg.xml properties, set 'Build Action' to 'Content' and 'Copy to Output Directory' to 'Copy if newer' - this will copy hibernate.cfg.xml into the build output folder (e.g. bin\Debug\netcoreapp2.1).

  1. Add your data provider package into the project, e.g. System.Data.SQLite.Core for SQLite, System.Data.SqlClient for SQL Server, Npgsql for PostgreSQL.

  2. To persist an entity into a database, the database needs to be created first. Use the following code sample to create a database, SQLite example:

var nhibernateConfigurator = new CoreDddSampleNhibernateConfigurator();
var configuration = nhibernateConfigurator.GetConfiguration();
var connectionString = configuration.Properties["connection.connection_string"];

using (var connection = new SQLiteConnection(connectionString))
{
    connection.Open();
    await new SchemaExport(configuration).ExecuteAsync(
        useStdOut: true,
        execute: true,
        justDrop: false,
        connection: connection,
        exportOutput: null
    );
}

You can replace SQLiteConnection by SqlConnection for SQL Server or NpgsqlConnection for PostgreSQL. This code sample uses NHibernate SchemaExport feature which is able to generate SQL create database script from the domain entities code and execute it against the database.

  1. Persist a Ship entity using the following code:
using (var unitOfWork = new NhibernateUnitOfWork(nhibernateConfigurator))
{
    unitOfWork.BeginTransaction();

    var shipRepository = new NhibernateRepository<Ship>(unitOfWork);

    try
    {
        var ship = new Ship("ship name", tonnage: 10m);
        await shipRepository.SaveAsync(ship);

        await unitOfWork.CommitAsync();

        Console.WriteLine("Ship entity was persisted.");
    }
    catch
    {
        await unitOfWork.RollbackAsync();
        throw;
    }
}

This code sample uses CoreDdd NhibernateUnitOfWork which is a transactional wrapper around NHibernate session. The entity persistence sample above is available here as .NET Core console app.

You can’t perform that action at this time.