Если вы начинаете все с нуля, вы можете ввести свой элемент "Id" как Guid
вместо ObjectId
. Это предпочтительнее, потому что тогда ваша модель не должна ссылаться на MongoDB.Bson
, возможно, превращая ее в класс POCO. Вам даже не нужен атрибут [BsonId]
, если вы называете член "Id", и это лучше не делать по вышеупомянутой причине.
Если вы уже застряли, используя ObjectId
в своих классах POCO и - осознав трудности - хотели бы изменить тип "Id" (в вашем классе), но не можете изменить тип из «_id» (в ваших данных) вы можете сделать собственный сериализатор:
public class SafeObjectIdSerializer: ObjectIdSerializer
{
public SafeObjectIdSerializer() : base() { }
public override ObjectId Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonReader = context.Reader;
var bsonType = bsonReader.GetCurrentBsonType();
switch (bsonType)
{
case BsonType.Binary: {
var value = bsonReader
.ReadBinaryData()
.AsGuid
.ToString()
.Replace("-", "")
.Substring(0, 24);
return new ObjectId(value);
}
}
return base.Deserialize(context, args);
}
}
Как упомянул MiddleTommy, переход с Guid
на ObjectId
с потерями, но в зависимости от того, как вы используете это поле, это может не быть проблемой. Выше используются первые 24 шестнадцатеричных символа и отбрасываются оставшиеся 8. Если вы храните случайные значения ObjectId
, а не, скажем, преобразование ObjectId в инкрементные целые числа, у вас все будет в порядке.
Если вы также хотите начать писать ObjectId
как Guid
, похоже, что ничего не мешает смешивать типы "_id", пока вы откатываетесь на base.Deserialize()
, но я мог бы быть неправильно, и это может иметь значение в зависимости от вашей реализации. Документация не говорит так или иначе. Для этого вы можете добавить это переопределение к вышеуказанному классу:
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, ObjectId value)
{
var bsonWriter = context.Writer;
var guidString = value
.ToString()
.Insert(8, "-")
.Insert(13, "-")
.Insert(18, "-")
.Insert(23, "-") + "00000000";
var asGuid = new Guid(guidString);
bsonWriter.WriteBinaryData(new BsonBinaryData(asGuid));
}
Чтобы сделать это вашим глобальным десериализатором:
public class CustomSerializationProvider : IBsonSerializationProvider
{
public IBsonSerializer GetSerializer(Type type)
{
if (type == typeof(ObjectId))
{
return new SafeObjectIdSerializer();
}
//add other custom serializer mappings here
//to fall back on the default:
return null;
}
}
Тогда где-то, где он будет вызываться только один раз, как ваш Global.asax Application_Start()
BsonSerializer.RegisterSerializationProvider(new CustomSerializationProvider());