C# mongodb 使用记录的强类型 ID
C# mongodb with strongly typed ID using records
我正在使用带有 Mongo 的 C#9 记录来处理强类型 ID。我已经成功地进行了插入工作,但读取时抛出异常(见下文)。
这些是模型定义。很简单,TestModel
有一个 TestModelId
类型为 StronglyTypedId<Guid>
.
public record TestModel(TestModelId Id, string value, string? value1);
public record TestModelId(Guid Id) : StronglyTypedId<Guid>(Id);
public abstract record StronglyTypedId<TValue>(TValue Id) where TValue : notnull;
这些需要注册序列化提供程序和序列化程序 class。
注册:
var guidSerializer = BsonSerializer.SerializerRegistry.GetSerializer<Guid>();
BsonSerializer.RegisterSerializationProvider(new IdSerializationProvider(guidSerializer));
序列化程序:
public class IdSerializationProvider : IBsonSerializationProvider
{
private IBsonSerializer<Guid> guidSerializer;
public IdSerializationProvider(IBsonSerializer<Guid> guidSerializer)
{
this.guidSerializer = guidSerializer;
}
public IBsonSerializer? GetSerializer(Type type)
{
if(type.BaseType != null && type.BaseType == typeof(StronglyTypedId<Guid>))
return new TestModelSerializer(type, guidSerializer);
return null;
}
}
public class TestModelSerializer : SerializerBase<StronglyTypedId<Guid>>
{
private readonly Type targetType;
private readonly IBsonSerializer<Guid> guidSerializer;
public TestModelSerializer(Type targetType, IBsonSerializer<Guid> guidSerializer)
{
this.targetType = targetType;
this.guidSerializer = guidSerializer;
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, StronglyTypedId<Guid> value)
{
guidSerializer.Serialize(context, args, value.Id);
}
public override StronglyTypedId<Guid> Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var guid = guidSerializer.Deserialize(context, args);
var idType = Activator.CreateInstance(targetType, new object[] { guid });
return (idType as StronglyTypedId<Guid>)!;
}
}
下面用于插入新文档的代码有效。
MongoClient dbClient = new MongoClient("mongodb://localhost:27017");
IMongoCollection<TestModel> collection = dbClient.GetDatabase("test").GetCollection<TestModel>("testmodel");
TestModel model = new TestModel(new TestModelId(Guid.NewGuid()), "test", "test");
collection.InsertOne(model);
但是使用 Find
读取会抛出异常:
System.InvalidOperationException: 'The operands for operator 'Equal' do not match the parameters of method 'op_Equality'.'
TestModel found = collection.Find(x => x.Id == model.Id).FirstOrDefault();
我试过使用 Equals
代替,像这样
TestModel found = collection.Find(x => x.Id.Equals(model.Id)).FirstOrDefault();
但这是抛出另一个异常:System.ArgumentException: 'Method 'Boolean Equals(WebApplication2.Controllers.TestModelId)' declared on type 'WebApplication2.Controllers.TestModelId' cannot be called with instance of type 'WebApplication2.Controllers.StronglyTypedId`1[System.Guid]''
我不确定那里发生了什么,类型定义很清楚,但由于某种原因似乎类型不匹配?我尝试 google 任何解决方案,但找不到任何东西。
我没有找到导致异常的原因,但我找到了解决方法:
var filter = Builders<TestModel>.Filter.Eq("_id", model.Id.Id);
TestModel found = collection.Find(filter).FirstOrDefault();
我正在使用带有 Mongo 的 C#9 记录来处理强类型 ID。我已经成功地进行了插入工作,但读取时抛出异常(见下文)。
这些是模型定义。很简单,TestModel
有一个 TestModelId
类型为 StronglyTypedId<Guid>
.
public record TestModel(TestModelId Id, string value, string? value1);
public record TestModelId(Guid Id) : StronglyTypedId<Guid>(Id);
public abstract record StronglyTypedId<TValue>(TValue Id) where TValue : notnull;
这些需要注册序列化提供程序和序列化程序 class。
注册:
var guidSerializer = BsonSerializer.SerializerRegistry.GetSerializer<Guid>();
BsonSerializer.RegisterSerializationProvider(new IdSerializationProvider(guidSerializer));
序列化程序:
public class IdSerializationProvider : IBsonSerializationProvider
{
private IBsonSerializer<Guid> guidSerializer;
public IdSerializationProvider(IBsonSerializer<Guid> guidSerializer)
{
this.guidSerializer = guidSerializer;
}
public IBsonSerializer? GetSerializer(Type type)
{
if(type.BaseType != null && type.BaseType == typeof(StronglyTypedId<Guid>))
return new TestModelSerializer(type, guidSerializer);
return null;
}
}
public class TestModelSerializer : SerializerBase<StronglyTypedId<Guid>>
{
private readonly Type targetType;
private readonly IBsonSerializer<Guid> guidSerializer;
public TestModelSerializer(Type targetType, IBsonSerializer<Guid> guidSerializer)
{
this.targetType = targetType;
this.guidSerializer = guidSerializer;
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, StronglyTypedId<Guid> value)
{
guidSerializer.Serialize(context, args, value.Id);
}
public override StronglyTypedId<Guid> Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var guid = guidSerializer.Deserialize(context, args);
var idType = Activator.CreateInstance(targetType, new object[] { guid });
return (idType as StronglyTypedId<Guid>)!;
}
}
下面用于插入新文档的代码有效。
MongoClient dbClient = new MongoClient("mongodb://localhost:27017");
IMongoCollection<TestModel> collection = dbClient.GetDatabase("test").GetCollection<TestModel>("testmodel");
TestModel model = new TestModel(new TestModelId(Guid.NewGuid()), "test", "test");
collection.InsertOne(model);
但是使用 Find
读取会抛出异常:
System.InvalidOperationException: 'The operands for operator 'Equal' do not match the parameters of method 'op_Equality'.'
TestModel found = collection.Find(x => x.Id == model.Id).FirstOrDefault();
我试过使用 Equals
代替,像这样
TestModel found = collection.Find(x => x.Id.Equals(model.Id)).FirstOrDefault();
但这是抛出另一个异常:System.ArgumentException: 'Method 'Boolean Equals(WebApplication2.Controllers.TestModelId)' declared on type 'WebApplication2.Controllers.TestModelId' cannot be called with instance of type 'WebApplication2.Controllers.StronglyTypedId`1[System.Guid]''
我不确定那里发生了什么,类型定义很清楚,但由于某种原因似乎类型不匹配?我尝试 google 任何解决方案,但找不到任何东西。
我没有找到导致异常的原因,但我找到了解决方法:
var filter = Builders<TestModel>.Filter.Eq("_id", model.Id.Id);
TestModel found = collection.Find(filter).FirstOrDefault();