我无法让我的模型将实体的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);
}
}
对于上面代码中的行// map Id property here
,我尝试了许多不同的配置Id映射的方法,但没有一种方法有效。我尝试过的方法以及调用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);
我做错了什么?我认为这是id处理的标准用例?
答案 0 :(得分:13)
这已经改变了,我使用的是最新的1.x驱动程序(Nuget包<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));
});
答案 1 :(得分:5)
找到答案:
cm.IdMemberMap
.SetRepresentation(BsonType.ObjectId)
.SetIdGenerator(StringObjectIdGenerator.Instance);
这允许我保存为本机ObjectId,并且仍然将C#中的Id表示为字符串。作为一个小问题,必须在查询之前解析id:
public Account GetAccountById(string id)
{
return _accounts.FindOneById(ObjectId.Parse(id));
}
2015年5月编辑
显然,自从我写这个答案后,司机已经改变了。上面的其他答案对于较新版本是正确的,但如果使用旧版本的驱动程序,仍然可以参考此答案。
答案 2 :(得分:2)
如果您希望在整个实体范围内进行相同类型的映射而无需反复重复,则可能需要使用约定:
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));
}
}
}
...然后用它代替所有自定义映射:
ConventionPack cp = new ConventionPack();
cp.Add(new StringObjectIdIdGeneratorConventionThatWorks());
ConventionRegistry.Register("TreatAllStringIdsProperly", cp, _ => true);