MongoDB ObjectIds exposure

I have a data layer (contains MongoDB connection), a domain layer (contains repositories and entities) and a service layer (contains services and models)

Now, since my objects are using ObjectIds, they require MongoDB knowledge (is that fine?)

My services receive repository calls that return these entities and then convert them to models. This causes my service layer to require knowledge of MongoDB due to the ObjectId Property for objects.

Is there a way to avoid this? I heard that I can use a string of type Id as a type, and when storing data, MongoDB converts that to ObjectId?

+3


source to share


2 answers


Sometimes it can be confusing to match just the ID, and also what happens in case you might have a different ObjectId (possibly a reference) in the same object?

Ok, you can make a map for objectId using map conditionally above config . see the following implementation:

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);
        }

    }

      



so for this case, any Id and any other property that ends with objectId will map to objectId, so you can leave your ids objects as a string and the driver will handle the conversion for you, this is more convenient if you don't want to carry mongodb dependencies between most of your layers on your system.

you can change the convention to whatever you want, I just wanted you to see this function.

+1


source


Short version: yes, use the whole line.

If you're ok with annotations, use:

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

      

Otherwise, you can use a classmap:

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

      

Long version:



It is advisable to use something opaque that is not directly related to the database in your model and service layer as much as possible (when possible).

There used to be primary key ids where there are usually large numbers, which were then mapped to the primary key column of the number in the database. However, when assigning a new ID to a new object, you must check the database validation to ensure a unique ID. There are many methods, from LO-HI generators, for auto_increment columns, for sequences, etc.

With NoSQL and the need for more parallelism, most applications now use UUIDs or variations thereof, since an ID can be generated with reasonable probabilities, it will be unique, without having to query the database if it is truly unique, or use sequences or the like that are bottlenecks in an application that scales horizontally.

MongoDB is irrelevant and uses ObjectId, which is a kind of UUID.

These identifiers (both mongo and others) can always be represented as strings, usually a HEX representation of the bytes that make up the key. So in your model use String as identifiers, in your service layer it's the same, in your data layer, convert it to whatever format for your base database implementation, MongoDB in this case.

+3


source







All Articles