mongodb - 使用成员编号保存文档,而不是使用 protobuf-net 和 MongoDB 的名称
问题描述
我在某处看到使用 Go MongoDB 驱动程序可以使用订单号而不是字段名称保存文档。
他们最终在数据库中得到了这个:
{
"3": "foo",
"10": 1,
"33": 123456
"107": {
"2": "bar",
"1": "foo"
}
}
我喜欢这个主意!因此,我试图找到一种对 MongoDB C# 驱动程序执行相同操作的方法。
我有下面的代码,但我不确定我应该从 protobut-net 带来什么来获取会员订单号。
var pack = new ConventionPack();
pack.AddMemberMapConvention("numbered", m => m.SetElementName( WHAT TO PUT HERE ));
ConventionRegistry.Register("numbered", pack, type => true);
SetElementName
接受一个字符串参数。
如何从 protobuf-net 中获取成员的订单号?
像...Member.Order.ToString()
我不知道这整件事是否是个好主意,但我想测试一下。
谢谢
- 更新 -
只是为了添加更多信息。我正在为我的模型使用继承来使用泛型。
[BsonDiscriminator("Base", RootClass = true)]
[DataContract]
public abstract class Base
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
[ProtoMember(1)]
public string Id { get; set; }
[BsonDateTimeOptions]
[ProtoMember(2)]
public DateTime CreatedDate { get; private set; } = DateTime.UtcNow;
[BsonDateTimeOptions]
[ProtoMember(3)]
public DateTime UpdatedDate { get; set; } = DateTime.UtcNow;
}
[ProtoContract]
public class Todo : Base
{
[ProtoMember(10)]
public string Title { get; set; }
[ProtoMember(20)]
public string Content { get; set; }
[ProtoMember(30)]
public string Category { get; set; }
}
我添加了这一行,如 protobuf-net 文档中所示:
RuntimeTypeModel.Default[typeof(Base)].AddSubType(42, typeof(Todo));
因此,有了这个以及 Marc 显示的获取成员编号的内容,我最终在 MongoDB 中拥有了一个自定义约定类,<T>
因此我可以将它用于其他对象:
public class NumberedElementNameConvention<T> : ConventionBase, IMemberMapConvention where T : Base
{
public void Apply(BsonMemberMap memberMap)
{
var members = RuntimeTypeModel.Default[typeof(T)].GetFields();
foreach (var member in members)
{
memberMap.SetElementName(member.FieldNumber.ToString());
}
}
}
该公约的注册是这样完成的:
var pack = new ConventionPack { new NumberedElementNameConvention<Todo>() };
ConventionRegistry.Register("NumberedName", pack, type => true);
运行后我得到这个错误:
Grpc.AspNetCore.Server.ServerCallHandler[6] 执行服务方法“CreateOne”时出错。MongoDB.Bson.BsonSerializationException:类型为“Nnet.Models.Base”的属性“UpdatedDate”不能使用元素名称“30”,因为它已被属性“CreatedDate”使用...
另外,当我运行下面的代码时,我希望得到 Todo 对象的所有成员。
var members = RuntimeTypeModel.Default[typeof(Todo)].GetFields();
foreach (var member in members)
{
Console.WriteLine($"{member.FieldNumber}: {member.Member.Name}");
}
但是,我没有得到从 Base 对象继承的那些:
❯ dotnet run
10:标题
20:内容
30:类别
解决方案
protobuf-net 的字段元数据可从RuntimeTypeModel
API 获得,例如:
var members = RuntimeTypeModel.Default[yourType].GetFields();
foreach (var member in members)
{
Console.WriteLine($"{member.FieldNumber}: {member.Member.Name}");
}
.FieldNumber
给出 protobuf 字段编号,并.Member
给出MemberInfo
相应字段或属性的。m => m.SetElementName( WHAT TO PUT HERE )
如果对同一个值进行多次评估,您可能希望进行某种级别的缓存m
,这样您就不会执行不必要的工作 - 但是:在您这样做之前,只需先向 lambda 添加一些日志记录,然后查看它获得的频率叫:如果不是太频繁,也许不用担心。
请注意,还有一个查找MetaType
允许通过以下方式进行查询MemberInfo
:
var member = RuntimeTypeModel.Default[yourType][memberInfo];
推荐阅读
- angular - Angular 通用服务的多个实例
- flutter - RenderFlex 孩子有非零的弹性错误/颤振
- android - 在 Android 中将多个 LiveData 对象聚合为一个 LiveData 聚合对象
- javascript - 如何按顺序处理 websocket 消息
- git - Github:从 PR 中删除添加的文件
- azure - 部署前 Azure clean $web
- reactjs - 使用自定义钩子封装 useEffect 和 AJAX 请求
- format - 如何在乳胶中漂浮长桌?
- android - 启动 geth 节点时应用程序在启动时崩溃
- architecture - 系统设计 观看直播的用户数