This repository contains an example of an Event Store built on Azure Cosmos DB.
It contains all demo code that I use in my Cosmos Event Sourcing talk. See here for the slidedeck.
Demo on YouTube: https://youtu.be/UejwRlmV6E4
The mssql branch contains code to have views written to MSSQL (contributed by marctalcott, thanks!)
(see the Readme.txt at https://github.com/marctalcott/CosmosEventSourcing/blob/main/src/Projections/MSSQL/Readme.DbScript.txt
In this example I want a MSSQL table that shows the current state of the Meter Aggregate. This is helpful in scenarios where you need to run quick ad hoc queries to view the current state.
You may want this instead of Cosmos views, or in addition to Cosmos views. For the example we keep the Cosmos views and have this as an additional way of viewing your current state.
create table Meter
(
MeterId nvarchar(255) not null primary key,
PostalCode nvarchar(255),
HouseNumber nvarchar(255),
IsActivated bit,
FailedActivationAttempts int,
LatestReadingDate datetime,
-- The next 2 lines should be on all tables. They allow code to decide if a change has been applied yet.
LogicalCheckPoint_lsn float not null,
LogicalCheckPoint_ItemIds nvarchar(max) not null
)
go
create unique index Meter_MeterId_uindex
on Meter (MeterId)
go
You will find it in Projections/MSSQL/DBSchema/esdemo3Context.cs
This Project already includes Projections/MSSQL/DBSchema/esdemo3Context.cs and Projections/MSSQL/DBSchema/Meter.cs
Once the table is created you can run this script in your 'Projections' project root folder, and it will create your SQL EF code for you.
You need to go to Projections/MSSQL/DBSchema/esdemo3Context.cs and set the connection string to match the database you created at Azure
If you alter the table and you want to udpdate your .Net models use this with your correct connection string You should run it from the terminal in the Projections folder location dotnet ef dbcontext scaffold "server=myServer;database=myDb;user=myUser;password=myPassword;" "Microsoft.EntityFrameworkCore.SqlServer" -v -f --schema dbo -o MSSQL/DbSchema
Have you ever wanted to change some of your events that were recorded in the event log. There are times this is valid in event sourcing. In my case we had a project where we got the Ubiquitous Language wrong. We had fundamental aggregate, which one part of the business used a particularly odd name for. Since this was the only part of the business we were exposed to at that point, we used their terminology, but later found out that it was not the most common name to be used by other parts of the business, nor did it make much sense to the dev team. So we wanted to change the name of an Aggregate (and therefore its events). If that was all, I might suggest you avoid re-writing the event history, but on top of that, this is such a core piece that nearly every other aggregate maintains an Id for the item. So migrating the code would involve touching almost every Aggregate, Event, View, and more. It also would mean maintaining logic to handle the old events by the first name, and the new events with the new name. And every aggregate would have to know how to apply both sets of events. And most views would have to be updated to handle both types of events. And new views were needed to reflect the new naming.
The cleaner option was to create a new set of events and aggregates and act as if we had named it correctly from the beginning (rather than having code to handle both types of events going forward).
Hence the Migrator.
To use the Migrator, you create a new set of events (I created Monitor events which will replace Meter events in this sample code). Run the Migration engine using the DemoScenariosForMigrator. And then run the individual tests within that same file. As Meter events are recorded you will see them get transformed into Monitor events and written into a separate container. Events that are not specifically transformed are also moved to the new container without making any changes to them.
You will still need to write your new events, but you can also basically refactor the rest of your code to use the new naming after the migration is done and you won't need to work with the old event names and the new events names simultaneously.
After you Migrate your code from one event container to another, you would probably like to run some type of tests to make sure that your new event container contains all the events you expect it to, and that all those events have the right names and properties. The Validator project allows you Validators (inherit from CosmosValidate.Validator) that can be used to compare an expected event to an actual event (similar to Assert.Equal in unit tests) to make sure that you have the events you expected. You only need to create code for events that differ from the originals. The default check would look to see that the new event matches the old event without any special logic added.
In the end you will have 2 containers with outputs ('pass' and 'fail'). If you only have data in your 'pass' container, then everything is as expected. If you have any data in your 'fail' container, then you should examine that, fix as needed, and re-run the validator.