如何告诉MongoDB C#驱动程序以字符串格式存储所有Guid?

时间:2012-12-12 11:38:51

标签: mongodb serialization mongodb-.net-driver

我目前正在将[BsonRepresentation(BsonType.String)]属性应用于我的域模型中的所有Guid属性,以便以字符串格式序列化这些属性。除了令人厌倦之外,有时候这种情况并不常见,例如:使用自定义Wrapper<T>类:

public class Wrapper<T>
{
    public T Value { get; set; }

    // Further properties / business logic ...
}

TGuid时,Value属性将存储为UuidLegacy类型的二进制数据(任何类型为Guid的属性都不会存储用上面的属性装饰)。但是,我希望所有Guid,包括Wrapper<Guid>.Value,都表示为数据库中的字符串。

有没有办法告诉MongoDB C#驱动程序以字符串格式存储所有Guid

4 个答案:

答案 0 :(得分:6)

这可以使用惯例

来实现

有些事情:

var myConventions = new ConventionProfile();
myConventions.SetSerializationOptionsConvention(
    new TypeRepresentationSerializationOptionsConvention(typeof (Guid), BsonType.String));

BsonClassMap.RegisterConventions(myConventions, t => t == typeof (MyClass));

这应该在您的应用启动中的某个位置。

您可以在此处详细了解约定:http://www.mongodb.org/display/DOCS/CSharp+Driver+Serialization+Tutorial#CSharpDriverSerializationTutorial-Conventions

答案 1 :(得分:4)

虽然使用约定会起作用,但要注意两个重要的(和相关的)要点:

  1. filter参数是必需的,如果过滤器过于笼统(例如:t => true),则可能会覆盖其他已注册的约定。
  2. 请注意注册约定的顺序很重要,首先注册特定的过滤器并注册一般约定。
  3. 另一种选择是为类型Guid创建一个BSON类映射,它将表示设置为字符串:

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

    这应该在使用BsonSerializer进行任何读/写之前完成,否则将创建默认的Class Map,并且您将无法更改Class Map。

答案 2 :(得分:3)

在没有设置Convention的情况下全局执行此操作的替代方法(鉴于实际问题是有效的,我认为这是过度杀伤:“如何全局应用”)可以通过只需调用一行代码:

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

请确保这是MongoDb序列化配置中的第一件事(即使在注册类映射之前,基于约定的解决方案也是如此)。

就我个人而言,我认为这是一个更好的解决方案,而不是创建一个带有'always return true'谓词的约定,大多数似乎都在暗示。约定适用于更复杂的场景,以及对谓词实际使用的序列化配置集进行分组,并且多个Conventions捆绑到ConventionPack中。但是,对于简单地应用全局序列化格式,只需使用上面的代码行保持简单。

如果您以后确定您的合法Convention需要更改此规则,请注册它以覆盖我们设置的全局规则,就像您的Convention会覆盖< em>默认全局规则,设置为Guid's表示为BsonType.Binary。最后的结果是全局规则优先,其次是Convention,在适用自定义ConventionPack的情况下,它将覆盖我们的自定义全局规则 (基于您的自定义谓词。)

答案 3 :(得分:0)

不推荐使用ConventionProfile。如果您不想全局应用规则,但仅针对特定类(这应该在您的应用启动中的某个位置):

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