gautema / CQRSlite

A lightweight framework to help creating CQRS and Eventsourcing applications in C#
Other
1.1k stars 266 forks source link

Snapshot aggregte returns an aggregate with default values. #103

Closed bdongus closed 4 years ago

bdongus commented 4 years ago

Hi.

Probably I am doing something wrong, but I have no idea what. This is my test code:

        // Arrange
        var guid = Guid.NewGuid();
        var eventPublisher = new TestEventPublisher();
        var eventStore = new EventStoreRepository(_unitOfWork, eventPublisher, new EventMapper());
        var snapshotStore = new SnapShotStoreRepository<SnapshotEntry>(_unitOfWork, new SnapshotMapper());
        var repository = new SnapshotRepository(snapshotStore, new DefaultSnapshotStrategy(), new Repository(eventStore), eventStore);
        var session = new Session(repository);
        var aggregate = new Product(guid, "MQT");

        // Act
        for (int i = 0; i < 123; i++) {
            aggregate.Describe(System.IO.Path.GetRandomFileName());
        }
        aggregate.Describe("idee5");
        await session.Add(aggregate).ConfigureAwait(false);
        await session.Commit().ConfigureAwait(false);
        var result = await session.Get<Product>(aggregate.Id).ConfigureAwait(false);

        // Assert
        Assert.Equal(aggregate.Version, result.Version);

My assert expects 125 but 0 is returned. The guid is the default guid. Not the aggregates guid.

What could cause that behaviour?

I am using version 1.32.1.

gautema commented 4 years ago

Hi. From what I see, everything looks correct.

Does it work if you don’t use snapshots? So just use the repository? If so, my guess is that there is something wrong in the snapshots restore method or the event store.

It’s very hard for me to know without being able to debug the code, but as said, it looks correct from here.

bdongus commented 4 years ago

Hi, It did work before switching the aggregate to a snapshot aggregate.

The snapshot store returns the snapshot with version 125. The event store then returns an empty array. There is no event beyond version 125. The "RestoreFromSnapshot" method on my aggregate root is never called.

Guess that's the problem. Any ideas why this happens?

gautema commented 4 years ago

That’s strange. Can you debug into CQRSlite and see what happens? Is the Restore method called in the SnapshotAggregateroot? And what happens inside TryRestoreAggregateFromSnapshot in snapshotrepostiory.

Unfortunately I’m on vacation without a computer until the weekend, so can’t really debug to much myself.

bdongus commented 4 years ago

I will downlaod the source and debug this. Enjoy your vacation.

bdongus commented 4 years ago

Inside TryRestoreAggregateFromSnapshot

aggregate.Invoke("Restore", snapshot);

is executed. In the DynamicInvoker

            var exists = _cachedMembers.TryGetValue(hash, out var method);
            if (exists) return method?.Invoke(obj, args);

exists is true, but method is null.

This happens because I use different types in the store (SnapshotEntry) and in the snapshot aggregate (GenericSnapshot). In the SQL database I store all types of snapshots in the same structure (aggregate data as JSON string). Using the I SnapshotEntry everywhere would to leak infrastructure details into the domain.

Might not be the best idea to handle this. Which leads me to a question: What is the recommended way to work with snapshots seralizing/deserializing them to/from some kind of disk storage? Is there a working sample?

bdongus commented 4 years ago

ooops ... misclicked and closed the issue accidently.

gautema commented 4 years ago

Hi. There are as far as I know no working samples in the wild. I have only used it in closed source projects myself, and haven't actually used snapshotting in a while.

I haven't ever tried using a generic snapshot or anything not made for each aggregate so I'm a bit lost here.

Would it work with regular dynamic invoking? If so, maybe I could find a way to invoke if method is null in the code quoted above.

bdongus commented 4 years ago

Sorry for the delay. I think my way isn't as smart as I thought. I will use dedicated snapshots per aggregate. If I stumble upon something else, I'll ask again.

Have a nice week.