使用 MongoDB 时如何按约定应用 BsonRepresentation 属性
How to apply BsonRepresentation attribute by convention when using MongoDB
我正在尝试将 [BsonRepresentation(BsonType.ObjectId)]
应用于所有表示为字符串的 ID,而不必用该属性修饰我的所有 ID。
我尝试添加 StringObjectIdIdGeneratorConvention
但似乎无法排序。
有什么想法吗?
您可以通过编程方式注册您打算用来表示 mongo 文档的 C# class。注册时您可以覆盖默认行为(例如将 id 映射到字符串):
public static void RegisterClassMap<T>() where T : IHasIdField
{
if (!BsonClassMap.IsClassMapRegistered(typeof(T)))
{
//Map the ID field to string. All other fields are automapped
BsonClassMap.RegisterClassMap<T>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Id).SetIdGenerator(StringObjectIdGenerator.Instance);
});
}
}
然后为每个要注册的 C# classes 调用此函数:
RegisterClassMap<MongoDocType1>();
RegisterClassMap<MongoDocType2>();
您要注册的每个 class 都必须实现 IHasIdField
接口:
public class MongoDocType1 : IHasIdField
{
public string Id { get; set; }
// ...rest of fields
}
需要注意的是,这不是全局解决方案,您仍然需要手动迭代 classes。
是的,我也注意到了。由于某些原因,StringObjectIdIdGeneratorConvention
的当前实现似乎不起作用。这是一个有效的方法:
public class Person
{
public string Id { get; set; }
public string Name { get; set; }
}
public class StringObjectIdIdGeneratorConventionThatWorks : ConventionBase, IPostProcessingConvention
{
/// <summary>
/// Applies a post processing modification to the class map.
/// </summary>
/// <param name="classMap">The class map.</param>
public void PostProcess(BsonClassMap classMap)
{
var idMemberMap = classMap.IdMemberMap;
if (idMemberMap == null || idMemberMap.IdGenerator != null)
return;
if (idMemberMap.MemberType == typeof(string))
{
idMemberMap.SetIdGenerator(StringObjectIdGenerator.Instance).SetSerializer(new StringSerializer(BsonType.ObjectId));
}
}
}
public class Program
{
static void Main(string[] args)
{
ConventionPack cp = new ConventionPack();
cp.Add(new StringObjectIdIdGeneratorConventionThatWorks());
ConventionRegistry.Register("TreatAllStringIdsProperly", cp, _ => true);
var collection = new MongoClient().GetDatabase("test").GetCollection<Person>("persons");
Person person = new Person();
person.Name = "Name";
collection.InsertOne(person);
Console.ReadLine();
}
}
我正在尝试将 [BsonRepresentation(BsonType.ObjectId)]
应用于所有表示为字符串的 ID,而不必用该属性修饰我的所有 ID。
我尝试添加 StringObjectIdIdGeneratorConvention
但似乎无法排序。
有什么想法吗?
您可以通过编程方式注册您打算用来表示 mongo 文档的 C# class。注册时您可以覆盖默认行为(例如将 id 映射到字符串):
public static void RegisterClassMap<T>() where T : IHasIdField
{
if (!BsonClassMap.IsClassMapRegistered(typeof(T)))
{
//Map the ID field to string. All other fields are automapped
BsonClassMap.RegisterClassMap<T>(cm =>
{
cm.AutoMap();
cm.MapIdMember(c => c.Id).SetIdGenerator(StringObjectIdGenerator.Instance);
});
}
}
然后为每个要注册的 C# classes 调用此函数:
RegisterClassMap<MongoDocType1>();
RegisterClassMap<MongoDocType2>();
您要注册的每个 class 都必须实现 IHasIdField
接口:
public class MongoDocType1 : IHasIdField
{
public string Id { get; set; }
// ...rest of fields
}
需要注意的是,这不是全局解决方案,您仍然需要手动迭代 classes。
是的,我也注意到了。由于某些原因,StringObjectIdIdGeneratorConvention
的当前实现似乎不起作用。这是一个有效的方法:
public class Person
{
public string Id { get; set; }
public string Name { get; set; }
}
public class StringObjectIdIdGeneratorConventionThatWorks : ConventionBase, IPostProcessingConvention
{
/// <summary>
/// Applies a post processing modification to the class map.
/// </summary>
/// <param name="classMap">The class map.</param>
public void PostProcess(BsonClassMap classMap)
{
var idMemberMap = classMap.IdMemberMap;
if (idMemberMap == null || idMemberMap.IdGenerator != null)
return;
if (idMemberMap.MemberType == typeof(string))
{
idMemberMap.SetIdGenerator(StringObjectIdGenerator.Instance).SetSerializer(new StringSerializer(BsonType.ObjectId));
}
}
}
public class Program
{
static void Main(string[] args)
{
ConventionPack cp = new ConventionPack();
cp.Add(new StringObjectIdIdGeneratorConventionThatWorks());
ConventionRegistry.Register("TreatAllStringIdsProperly", cp, _ => true);
var collection = new MongoClient().GetDatabase("test").GetCollection<Person>("persons");
Person person = new Person();
person.Name = "Name";
collection.InsertOne(person);
Console.ReadLine();
}
}