How can I tell the MongoDB C# driver to store all Guids in string format?

前端 未结 4 623
逝去的感伤
逝去的感伤 2021-01-13 08:47

I\'m currently applying the [BsonRepresentation(BsonType.String)] attribute to all Guid properties in my domain models to have those properties ser

相关标签:
4条回答
  • 2021-01-13 09:17

    This can be achieved using Conventions

    Something along the lines of:

    var myConventions = new ConventionProfile();
    myConventions.SetSerializationOptionsConvention(
        new TypeRepresentationSerializationOptionsConvention(typeof (Guid), BsonType.String));
    
    BsonClassMap.RegisterConventions(myConventions, t => t == typeof (MyClass));
    

    This should go somewhere in your app startup.

    You can read more about conventions here: http://www.mongodb.org/display/DOCS/CSharp+Driver+Serialization+Tutorial#CSharpDriverSerializationTutorial-Conventions

    0 讨论(0)
  • 2021-01-13 09:17

    While using conventions will work, pay attention to two important (and related) points:

    1. The filter parameter is required, and if the filter is too general (for example: t => true), it can overwrite other registered conventions.
    2. Be aware that the order of registered conventions is important, first register specific filters and after register general conventions.

    Another option is to create a BSON Class Map for type Guid, which sets the representation to string:

    if (!BsonClassMap.IsClassMapRegistered(typeof(Guid))) {
        BsonClassMap.RegisterClassMap<Guid>(cm => {
            cm.AutoMap();
            cm.Conventions.SetSerializationOptionsConvention(new  TypeRepresentationSerializationOptionsConvention(typeof(Guid), BsonType.String));
        });
    }
    

    This should be done before any reading/writing using BsonSerializer, otherwise the default Class Map will be created, and you wont be able to change the Class Map.

    0 讨论(0)
  • 2021-01-13 09:30

    An alternative to performing this globally without setting a Convention (which I believe is overkill given the actual question was effectively: "how can this be applied globally") can be done by simply calling one line of code:

    BsonSerializer.RegisterSerializer(typeof(Guid), 
        new GuidSerializer(BsonType.String));
    

    Just make sure this is the first thing that fires in terms of MongoDb's serialization configuration (even before class maps are registered, the same is true for the convention based solutions posted).

    Personally I see this as a better solution than creating a convention with an 'always return true' predicate, that most seem to be suggesting. Conventions are great for more complex scenarios, and for grouping sets of serialization configurations, where the predicate is actually used, and multiple Conventions are bundled into a ConventionPack. But for simply applying a global serialization format, just keep it simple with the above line of code.

    If you later decide you have a legitimate Convention that requires a variation of this rule, just register it in order to overwrite the global rule we have set, just as your Convention would overwrite the default global rule, which is set to have Guid's represented as BsonType.Binary. The net result then would be the global rule taking precedence, followed by the Convention, which will overwrite our custom global rule only in such cases where the custom ConventionPack is applicable (based on your custom predicate).

    0 讨论(0)
  • 2021-01-13 09:36

    ConventionProfile was deprecated. If you don't want to apply the rule globally, but only for a specific class (this should go somewhere in your app startup):

    var pack = new ConventionPack { new GuidAsStringRepresentationConvention () };
    ConventionRegistry.Register("GuidAsString", pack, t => t == typeof (MyClass));
    
    public class GuidAsStringRepresentationConvention : ConventionBase, IMemberMapConvention
        {
            public void Apply(BsonMemberMap memberMap)
            {
                if (memberMap.MemberType == typeof(Guid))
                {
                    var serializer = memberMap.GetSerializer();
                    var representationConfigurableSerializer = serializer as IRepresentationConfigurable;
                    if (representationConfigurableSerializer != null)
                    {
                        var reconfiguredSerializer = representationConfigurableSerializer.WithRepresentation(BsonType.String);
                        memberMap.SetSerializer(reconfiguredSerializer);
                    }
                }
            }
        }
    
    0 讨论(0)
提交回复
热议问题