MongoDB


To use MongoDB - Read Model Store integration, the NuGet package CrystalSharp.MongoDb must be installed.

IMPORTANT

Kindly keep in mind that this particular configuration is intended for the purpose of storing read models in the read model store and reading the data from the read model stores. However, the configuration procedures for database integration, Event Store, and Sagas will be approached differently.

In order to integrate a read model store effectively, it is necessary to adhere to the following mandatory steps:

  • Register the implementation of the read model store.
  • Use the IReadModelStore interface for read model store operations.

Read Model Store Registration

Following is the code that illustrates how to register the implementation of the read model store in the Program.cs file:

“CustomerOrderReadModel.cs” class:

public class CustomerOrderReadModel : ReadModel<string>
{
    public string OrderCode { get; private set; }
    public decimal TotalPrice { get; private set; }
    public string Name { get; private set; }
    public string Address { get; private set; }

    public static CustomerOrderReadModel Create(Guid globalUId,
        string orderCode,
        decimal totalPrice,
        string name,
        string address)
    {
        return new CustomerOrderReadModel
        {
            GlobalUId = globalUId,
            OrderCode = orderCode,
            TotalPrice = totalPrice,
            Name = name,
            Address = address
        };
    }
}

“Program.cs” file:

MongoDbSettings mongoDbReadModelStoreSettings = new("CONNECTION-STRING", "DATABASE");

CrystalSharpAdapter.New(builder.Services)
    .AddCqrs(typeof(PlaceOrderCommandHandler))
    .AddMongoDbReadModelStore(mongoDbReadModelStoreSettings)
    .CreateResolver();

In the above code snippet, when initializing the Crystal Sharp framework, a call to an extension method is made AddMongoDbReadModelStore(mongoDbReadModelStoreSettings) for the read model store registration.

Store Read Model

To store read models in the read model store, the IReadModelStore interface is used. The following code illustrates how to create a read model from multiple tables:

public class PlaceOrderCommandHandler : CommandHandler<PlaceOrderCommand, PlaceOrderResponse>
{
    private readonly IMongoDbContext _dbContext;
    private readonly IReadModelStore<string> _readModelStore;

    public PlaceOrderCommandHandler(IMongoDbContext dbContext, IReadModelStore<string> readModelStore)
    {
        _dbContext = dbContext;
        _readModelStore = readModelStore;
    }

    public override async Task<CommandExecutionResult<PlaceOrderResponse>> Handle(PlaceOrderCommand request, CancellationToken cancellationToken = default)
    {
        Order order = Order.PlaceOrder(request.OrderCode, request.TotalPrice, request.CustomerGlobalUId);

        await _dbContext.SaveChanges(order, cancellationToken).ConfigureAwait(false);

        Customer customer = await _dbContext.Find<Customer>(order.CustomerGlobalUId, cancellationToken).ConfigureAwait(false);

        CustomerOrderReadModel customerOrder = CustomerOrderReadModel.Create(order.GlobalUId,
            order.OrderCode,
            order.TotalPrice,
            customer.Name,
            customer.Address);

        await _readModelStore.Store(customerOrder, cancellationToken).ConfigureAwait(false);

        PlaceOrderResponse response = new() { OrderId = order.GlobalUId };

        return await Ok(response);
    }
}

In the above code snippet, the IMongoDbContext and IReadModelStore<string> interfaces are injected into the PlaceOrderCommandHandler constructor. In the Handle method, a new order is placed and stored in the database. After storing the data in the database, a read model is generated from the Orders and Customers tables and stored in the read model store, and later it can be queried from a single source without additional joins.

Here, pay attention to _readModelStore.Store(customerOrder, cancellationToken), as this method will store the data in the read model store.

Retrieve the Data from Read Model Store

Following is the code that illustrates how to retrieve the data from read model store:

“OrderDetailsQuery.cs” class:

public class OrderDetailsQuery : IQuery<QueryExecutionResult<CustomerOrderReadModel>>
{
    public string GlobalUId { get; set; }
}

“OrderDetailsQueryHandler.cs” class:

public class OrderDetailsQueryHandler : QueryHandler<OrderDetailsQuery, CustomerOrderReadModel>
{
    private readonly IReadModelStore<string> _readModelStore;

    public OrderDetailsQueryHandler(IReadModelStore<string> readModelStore)
    {
        _readModelStore = readModelStore;
    }

    public override async Task<QueryExecutionResult<CustomerOrderReadModel>> Handle(OrderDetailsQuery request, CancellationToken cancellationToken = default)
    {
        CustomerOrderReadModel customerOrder = _readModelStore.Find<CustomerOrderReadModel>(request.GlobalUId, cancellationToken).ConfigureAwait(false);

        return await Ok(customerOrder);
    }
}

In the above code snippet, the IReadModelStore<string> interface has been injected into the OrderDetailsQueryHandler constructor, and then in the Handle method, the read model store has been used to retrieve the data _readModelStore.Find<OrderReadModel>(request.GlobalUId, cancellationToken).ConfigureAwait(false).