MongoDB ObjectIds exposure

本文关键字:exposure ObjectIds MongoDB | 更新日期: 2023-09-27 18:23:39

我有一个数据层(包含到MongoDB的连接)、一个域层(包含repo和实体)和一个服务层(包含服务和模型)

现在,因为我的实体使用ObjectId,所以它们需要MongoDB的知识(这可以吗?)

我的服务调用返回这些实体的存储库,然后将它们转换为模型。这导致我的服务层需要了解MongoDB,因为实体上有ObjectId属性。

有什么办法可以避免这种情况吗?我听说我可以使用我的Id作为类型字符串,当存储数据时,MongoDB会将其转换为ObjectId吗?

MongoDB ObjectIds exposure

短版本:是的,在任何地方都使用String。

如果你对注释满意,那么使用:

[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }

否则,您可以使用类映射:

BsonClassMap.RegisterClassMap<i_YourModel>(cm =>
 {
  cm.AutoMap();
  cm.SetIdMember(cm.GetMemberMap(x => x.Id)
    .SetIdGenerator(StringObjectIdGenerator.Instance));
 }
);

长版本:

建议在模型和服务层中尽可能多地(在可能的情况下)使用不透明的、不直接连接到底层数据库实现的东西。

以前,主键ID通常是大数字,然后映射到数据库上的数字主键列。然而,当将新id分配给新实体时,必须对数据库进行检查,以确保具有唯一的id。存在许多技术,从LO-HI id生成器到auto_increment列,再到序列等

有了NoSQL,以及对更多并行性的需求,大多数应用程序现在都在使用UUID或其变体,因为ID可以以合理的概率生成,它将是唯一的,而不必询问数据库它是否真的是唯一的或使用序列等,这是横向扩展应用程序中的瓶颈。

MongoDB没有区别,它使用的ObjectId是一种UUID。

这些id(mongo和其他id)总是可以表示为字符串,通常是组成密钥的字节的十六进制表示。因此,在您的模型中,使用String作为id,在服务层中也是如此,在数据层中,将其转换为更适合底层数据库实现的任何格式,在本例中为MongoDB。

有时只映射Id可能会令人困惑,而且在同一实体中可能有另一个objectId(可能是引用)的情况下会发生什么?

您可以使用映射约定而不是配置模式来为objectId制作映射。看看以下实现:

public static class MongoDbConventionRegistry
{
    public static void Register()
    {
        var conventionPack = new ConventionPack {new StringObjectIdMemberMapConvention()};            
        ConventionRegistry.Register("CustomConventions", conventionPack, t => t.FullName.StartsWith("YourNamespace.Model.Entities.etc")); 
     }
 }
public class StringObjectIdMemberMapConvention : IMemberMapConvention
{
    private  readonly Regex _memberMatchRegex = new Regex(@"(^Id$)|(.+ObjectId?$)",RegexOptions.Compiled); // you can change this regex to match the convention you want
    public string Name {
            get { return "StringObjectId"; }
        }
        public void Apply(BsonMemberMap memberMap)
        {
            if (memberMap == null)
                return;
            if(memberMap.MemberType == typeof(string) && _memberMatchRegex.IsMatch(memberMap.ElementName) )
                memberMap.SetRepresentation(BsonType.ObjectId);
        }
    }

因此,在这种情况下,任何Id和以objectId结尾的任何其他属性都将映射到objectId中,因此您可以将实体Id保留为字符串,驱动程序将为您处理转换,当您不想在系统中的大多数层之间携带mongodb依赖关系时,这会更方便。

你可以把惯例改成任何你想要的,我只是想突出这个功能。