MongoDB C# 驱动程序 - 将集合序列化到接口
MongoDB C# driver - Serialize collection to interface
由于工作环境的限制,我正在 MongoDB 中实现一个粗略的事件源存储。我正在尝试从 Mongo 中获取 IClientEvents
的列表,如下所示:
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
,如 this SO post 中所述,但是当我注册第二个具体实现时它抛出异常,我已经为 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
方法。
我设法通过简单地将 IClientEvent
从接口更改为抽象 class 来让它工作。
由于工作环境的限制,我正在 MongoDB 中实现一个粗略的事件源存储。我正在尝试从 Mongo 中获取 IClientEvents
的列表,如下所示:
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
,如 this SO post 中所述,但是当我注册第二个具体实现时它抛出异常,我已经为 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
方法。
我设法通过简单地将 IClientEvent
从接口更改为抽象 class 来让它工作。