public void Serializes_access_to_an_aggregate_so_that_concurrent_transactions_succeed()
{
var user = new User();
user.Register("[email protected]", "password", Guid.NewGuid());
using (var session = OpenSession(CreateStore()))
{
session.Save(user);
user.ChangeEmail($"[email protected]");
session.SaveChanges();
}
Action updateEmail = () =>
{
using (var session = OpenSession(CreateStore()))
{
using (var transaction = new TransactionScope())
{
var userToUpdate = session.Get<User>(user.Id);
userToUpdate.ChangeEmail($"newemail_{userToUpdate.Version}@somewhere.not");
Thread.Sleep(100);
session.SaveChanges();
transaction.Complete();
}//Sql duplicate key (AggregateId, Version) Exception would be thrown here if history was not serialized
}
};
var tasks = 1.Through(20).Select(_ => Task.Factory.StartNew(updateEmail)).ToArray();
Task.WaitAll(tasks);
using (var session = OpenSession(CreateStore()))
{
var userHistory = ((IEventStoreReader)session).GetHistory(user.Id).ToArray();//Reading the aggregate will throw an exception if the history is invalid.
}
}