[英]MongoDB C# Driver - how to store _id as ObjectId but map to string Id property?
I'm having trouble getting my model to represent an entity's Id
property as a string but have it auto-generated and represented internally by MongoDb as a native ObjectId
.我在让我的模型将实体的
Id
属性表示为字符串时遇到问题,但它自动生成并由 MongoDb 在内部表示为本机ObjectId
。
class Account
{
public string Id { get; set; }
...
}
class AccountStore
{
static AccountStore()
{
BsonClassMap.RegisterClassMap<Account>(cm =>
{
cm.AutoMap();
cm.SetIgnoreExtraElements(true);
// map Id property here
});
}
public void Save(Account account)
{
_accounts.Save(account);
}
}
For the line // map Id property here
in the above code, I've tried numerous different ways of configuring the Id mapping and none have worked.对于上面代码中的
// map Id property here
行,我尝试了多种不同的方式来配置 Id 映射,但都没有奏效。 The ways I have tried, and the associated exceptions that are thrown when I call the Save
method, are:我尝试过的方法以及调用
Save
方法时抛出的相关异常是:
// Exception: No IdGenerator found.
cm.IdMemberMap
.SetRepresentation(BsonType.ObjectId);
// Exception: No IdGenerator found.
cm.IdMemberMap
.SetRepresentation(BsonType.String);
// Exception: Unable to cast object of type 'MongoDB.Bson.ObjectId' to type 'System.String'.
cm.IdMemberMap
.SetRepresentation(BsonType.ObjectId)
.SetIdGenerator(ObjectIdGenerator.Instance);
// Exception: Unable to cast object of type 'MongoDB.Bson.ObjectId' to type 'System.String'.
cm.IdMemberMap
.SetRepresentation(BsonType.String)
.SetIdGenerator(ObjectIdGenerator.Instance);
// Exception: Unable to cast object of type 'MongoDB.Bson.ObjectId' to type 'System.String'.
cm.IdMemberMap
.SetIdGenerator(ObjectIdGenerator.Instance);
What am I doing wrong?我究竟做错了什么? I thought this was a standard use case for id handling?
我认为这是 id 处理的标准用例?
This has changed, I'm using the latest 1.x driver (Nuget package <package id="mongocsharpdriver" version="2.0.0" targetFramework="net45" />
) and instead of using SetRepresentation
you set the serialiser.这已经改变了,我使用的是最新的 1.x 驱动程序(Nuget package
<package id="mongocsharpdriver" version="2.0.0" targetFramework="net45" />
),而不是使用SetRepresentation
设置序列化器。
public class RegistrationAttempt
{
public string AttemptId { get; set; }
}
BsonClassMap.RegisterClassMap<RegistrationAttempt>(cm =>
{
cm.AutoMap();
cm.MapIdProperty(c => c.AttemptId)
.SetIdGenerator(StringObjectIdGenerator.Instance)
.SetSerializer(new StringSerializer(BsonType.ObjectId));
});
Found the answer:找到答案:
cm.IdMemberMap
.SetRepresentation(BsonType.ObjectId)
.SetIdGenerator(StringObjectIdGenerator.Instance);
This allows me to save as a native ObjectId and still have the Id represented in C# as a string.这允许我保存为本机 ObjectId 并且仍然将 Id 在 C# 中表示为字符串。 As a small gotcha, the id must be parsed before being queried upon:
作为一个小问题,在查询 id 之前必须先解析它:
public Account GetAccountById(string id)
{
return _accounts.FindOneById(ObjectId.Parse(id));
}
Edit May 2015 2015 年 5 月编辑
Apparently the driver has changed since I wrote this answer.显然,自从我写下这个答案以来,驱动程序已经改变了。 The other answer above is correct for newer versions, but this answer can still be referred to if using a legacy version of the driver.
上面的另一个答案对于较新版本是正确的,但如果使用旧版本的驱动程序,仍然可以参考这个答案。
In case you want that very same kind of mapping across a whole range of entities without the need to repeat yourself over and over again you might want to use a convention:如果您希望在整个实体范围内进行完全相同的映射,而无需一遍又一遍地重复自己,您可能需要使用约定:
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));
}
}
}
...and then use it in lieu of all custom mappings: ...然后使用它代替所有自定义映射:
ConventionPack cp = new ConventionPack();
cp.Add(new StringObjectIdIdGeneratorConventionThatWorks());
ConventionRegistry.Register("TreatAllStringIdsProperly", cp, _ => true);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.