6

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

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

    // Further properties / business logic ...
}

Tis时Guid,该Value属性将存储为类型的二进制数据UuidLegacy(任何Guid未使用上述属性修饰的类型的属性也是如此)。但是,我希望所有Guids,包括Wrapper<Guid>.Value,都在数据库中表示为字符串。

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

4

4 回答 4

8

这可以使用约定来实现

类似于以下内容:

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

于 2012-12-13T16:22:30.540 回答
6

可以通过简单地调用一行代码来完成在不设置 a 的情况下全局执行此操作的替代方法Convention(鉴于实际问题是有效的,我认为这是过大的杀伤力:“如何在全局范围内应用它”):

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

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

就我个人而言,我认为这是一个比使用“总是返回真”谓词创建约定更好的解决方案,大多数人似乎都在暗示。约定非常适合更复杂的场景,也适用于对序列化配置集进行分组,其中实际使用了谓词,并且多个Conventions被捆绑到一个ConventionPack. 但是对于简单地应用全局序列化格式,只需使用上面的代码行保持简单。

如果您稍后决定您有一个合法Convention的需要此规则的变体,只需注册它以覆盖我们设置的全局规则,就像您Convention将覆盖默认的全局规则一样,该规则设置为Guid's表示为BsonType.Binary. 最终结果将是全局规则优先,然后是,在自定义适用的情况下(基于您的自定义谓词)Convention,它将覆盖我们的自定义全局规则。ConventionPack

于 2015-08-04T00:34:34.193 回答
4

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

  1. filter参数是必需的,如果过滤器过于笼统(例如t => true:),它可以覆盖其他注册的约定。
  2. 请注意,注册约定的顺序很重要,首先注册特定过滤器,然后注册一般约定。

另一种选择是为 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。

于 2013-03-18T12:15:55.690 回答
4

不推荐使用 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);
                }
            }
        }
    }
于 2015-10-21T11:29:45.860 回答