Prerequisites
The sample relies on the availability of a SQL Server named . and the existence of a database named Samples..
Code walk-through
This sample shows a simple client/server scenario.
- Clientsends a- StartOrdermessage to- Server.
- Serverstarts an- OrderSaga.
- OrderSagarequests a timeout with- CompleteOrderdata.
- When the CompleteOrdertimeout fires, theOrderSagapublishes anOrderCompletedevent.
- Serverthen publishes a message that the client has subscribed to.
- Clienthandles the- OrderCompletedevent.
NHibernate config
NHibernate is configured with the right driver, dialect, and connection string. Then, since NHibernate needs a way to map the class to the database table, the configuration code does this using the ModelMapper API. Finally, the configuration is used to run the endpoint.
var endpointConfiguration = new EndpointConfiguration("Samples.NHibernate.Server");
var persistence = endpointConfiguration.UsePersistence<NHibernatePersistence>();
// for SqlExpress use Data Source=.\SqlExpress;Initial Catalog=Samples.NHibernate;Integrated Security=True;Max Pool Size=100;Encrypt=false
var connectionString = @"Server=localhost,1433;Initial Catalog=Samples.NHibernate;User Id=SA;Password=yourStrong(!)Password;Max Pool Size=100;Encrypt=false";
var hibernateConfig = new Configuration();
hibernateConfig.DataBaseIntegration(x =>
{
    x.ConnectionString = connectionString;
    x.Dialect<MsSql2012Dialect>();
    x.Driver<MicrosoftDataSqlClientDriver>();
});
AddMappings(hibernateConfig);
persistence.UseConfiguration(hibernateConfig);
Order saga data
Note that to use NHibernate's lazy-loading feature, all properties on the saga data class must be virtual.
public class OrderSagaData :
    ContainSagaData
{
    public virtual Guid OrderId { get; set; }
    public virtual string OrderDescription { get; set; }
}
Order saga
public class OrderSaga :
    Saga<OrderSagaData>,
    IAmStartedByMessages<StartOrder>,
    IHandleTimeouts<CompleteOrder>
{
    static ILog log = LogManager.GetLogger<OrderSaga>();
    protected override void ConfigureHowToFindSaga(SagaPropertyMapper<OrderSagaData> mapper)
    {
        mapper.ConfigureMapping<StartOrder>(message => message.OrderId)
            .ToSaga(sagaData => sagaData.OrderId);
    }
    public Task Handle(StartOrder message, IMessageHandlerContext context)
    {
        Data.OrderId = message.OrderId;
        var orderDescription = $"The saga for order {message.OrderId}";
        Data.OrderDescription = orderDescription;
        log.Info($"Received StartOrder message {Data.OrderId}. Starting Saga");
        var shipOrder = new ShipOrder
        {
            OrderId = message.OrderId
        };
        log.Info("Order will complete in 5 seconds");
        var timeoutData = new CompleteOrder
        {
            OrderDescription = orderDescription
        };
        return Task.WhenAll(
            context.SendLocal(shipOrder),
            RequestTimeout(context, TimeSpan.FromSeconds(5), timeoutData)
        );
    }
    public Task Timeout(CompleteOrder state, IMessageHandlerContext context)
    {
        log.Info($"Saga with OrderId {Data.OrderId} completed");
        var orderCompleted = new OrderCompleted
        {
            OrderId = Data.OrderId
        };
        MarkAsComplete();
        return context.Publish(orderCompleted);
    }
}
Handler using ISession
The handler uses the ISession instance to store business data.
public class ShipOrderHandler :
    IHandleMessages<ShipOrder>
{
    public Task Handle(ShipOrder message, IMessageHandlerContext context)
    {
        var session = context.SynchronizedStorageSession.Session();
        var orderShipped = new OrderShipped
        {
            Id = message.OrderId,
            ShippingDate = DateTime.UtcNow,
        };
        session.Save(orderShipped);
        return Task.CompletedTask;
    }
}
The database
Data in the database is stored in three different tables.
The saga data
- IContainSagaData.maps to the OrderSagaData primary key and unique identifier column- Id - Id.
- IContainSagaData.and- Originator - IContainSagaData.map to columns of the same name with type- OriginalMessageId - varchar(255).
- Custom properties on SagaData, in this case OrderDescriptionandOrderId, are also mapped to columns with the same name and the respecting types.

The handler stored data
