Драйвер MongoDB C # - Сериализация коллекции для интерфейса - PullRequest
0 голосов
/ 18 октября 2018

Из-за ограничений среды на работе я внедряю черновой магазин Event Sourcing в MongoDB.Я пытаюсь получить список IClientEvents из Mongo, например так:

 var events = await _db.GetCollection<IClientEvent>("ClientEvents").FindAsync(c => c.ClientId == clientId);

Я получаю следующее исключение при запуске вышеупомянутого метода хранилища:

Message: System.InvalidOperationException : {document}.ClientId is not supported.

Интерфейс IClientEvent определяется как:

public interface IClientEvent
{
    Guid Id { get; set; }
    long TimeStamp { get; set; }
    Guid ClientId { get; set; }
}

public class ClientChangedEvent : IClientEvent
{
    public Guid Id { get; set; }
    public long TimeStamp { get; set; }
    public Guid ClientId { get; set; }

    public IEnumerable<Change> Changes;
    // ... other properties for the event
}

В одной коллекции будет храниться много разных типов событий, каждый из которых будет реализовывать IClientEvent.Я хочу просто получить в один вызов все события, которые произошли с Клиентом clientId.

Я зарегистрировал все конкретные реализации IClientEvent и даже добавил собственный дискриминатор:

        var clientEventsDiscriminator = new ClientEventsMongoDiscriminatorConvention();
        BsonSerializer.RegisterDiscriminatorConvention(typeof(IClientEvent),clientEventsDiscriminator);
        BsonClassMap.RegisterClassMap<ClientChangedEvent>();
        BsonSerializer.RegisterDiscriminatorConvention(typeof(ClientChangedEvent), clientEventsDiscriminator);

Я даже пытался зарегистрировать ImpliedImplementationInterfaceSerializer, как упомянуто в этом посте SO , но он выдает исключение, когда я регистрирую 2-ю конкретную реализацию, для которой я уже зарегистрировал сериализатор для IClientEvent.

Не уверен, куда идти отсюда.Любая помощь очень ценится!

- РЕДАКТИРОВАТЬ для получения большего кода:

Вот полный регистрационный код:

        var clientEventsDiscriminator = new ClientEventsMongoDiscriminatorConvention();
        BsonSerializer.RegisterDiscriminatorConvention(typeof(IClientEvent),clientEventsDiscriminator);

        clientEventsDiscriminator.AddEventType<ClientChangedEvent>();
        BsonClassMap.RegisterClassMap<ClientChangedEvent>();
        BsonSerializer.RegisterDiscriminatorConvention(typeof(ClientChangedEvent), clientEventsDiscriminator);

        clientEventsDiscriminator.AddEventType<ClientAddedEvent>();
        BsonClassMap.RegisterClassMap<ClientAddedEvent>();
        BsonSerializer.RegisterDiscriminatorConvention(typeof(ClientAddedEvent), clientEventsDiscriminator);

Вот дискриминатор:

    public class ClientEventsMongoDiscriminatorConvention : IDiscriminatorConvention
{
    private Dictionary<string, Type> _eventTypes = new Dictionary<string, Type>();

    public string ElementName => "_eventType";

    public BsonValue GetDiscriminator(Type nominalType, Type actualType)
    {
        return GetDiscriminatorValueForEventType(actualType);
    }

    public Type GetActualType(IBsonReader bsonReader, Type nominalType)
    {
        var bookmark = bsonReader.GetBookmark();
        bsonReader.ReadStartDocument();
        if (!bsonReader.FindElement(ElementName))
        {
            throw new InvalidCastException($"Unable to find property '{ElementName}' in document. Cannot map to an EventType.");
        }

        var value = bsonReader.ReadString();
        bsonReader.ReturnToBookmark(bookmark);

        if (_eventTypes.TryGetValue(value, out var type))
        {
            return type;
        }

        throw new InvalidCastException($"The type '{value}' has not been registered with the '{nameof(ClientEventsMongoDiscriminatorConvention)}'.");
    }

    private string GetDiscriminatorValueForEventType(Type type)
    {
        var indexOfEventWord = type.Name.IndexOf("Event");
        if (indexOfEventWord == -1)
        {
            return type.Name;
        }
        return type.Name.Substring(0, indexOfEventWord);
    }

    public void AddEventType<T>()
    {
        var discriminatorName = GetDiscriminatorValueForEventType(typeof(T));
        _eventTypes.TryAdd(discriminatorName, typeof(T));
    }
}

При запуске кода кажется, что он никогда не достиг метода GetActualType дискриминатора.

1 Ответ

0 голосов
/ 29 октября 2018

Мне удалось заставить его работать, просто изменив IClientEvent с интерфейса на абстрактный класс.

...