Мы используем MongoDb для хранения атрибутов продукта и создали собственный сериализатор массивов, чтобы взять словарь и сериализовать его в пользовательском формате. Формат принимает ключ и значение каждого словаря и сохраняет его как отдельный элемент массива, разделенный двоеточием.Как реализовать TryGetItemSerializationInfo в сериализаторе массива Bson?
класса Пример продукта
public class Product
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public string Name { get; set; }
[BsonSerializer(typeof(ProductAttributeSerializer))]
public Dictionary<string, string> Attributes { get; set; } = new Dictionary<string, string>();
}
Пример данных с форматом пользовательского массива
{
"_id" : ObjectId("56d94ee01992d148b4c10d59"),
"Name" : "My Product",
"Attributes" : [
"Colour:Blue",
"Gender:Mens"
]
}
Вот наш сериализатору
[BsonSerializer(typeof(ProductAttributeSerializer))]
public class ProductAttributeSerializer : IBsonSerializer, IBsonArraySerializer
{
public Type ValueType { get { return typeof(Dictionary<string, string>); } }
public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var type = context.Reader.GetCurrentBsonType();
var attributes = new Dictionary<string, string>();
switch (type)
{
case BsonType.Array:
context.Reader.ReadStartArray();
while (context.Reader.ReadBsonType() != BsonType.EndOfDocument)
{
string[] splitValues = context.Reader.ReadString().Split(':');
attributes.Add(splitValues[0], splitValues[1]);
}
context.Reader.ReadEndArray();
return attributes;
default:
throw new NotImplementedException($"No implementation to deserialize {type}");
}
}
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
{
var attributes = value as Dictionary<string, string>;
if (attributes != null)
{
context.Writer.WriteStartArray();
foreach (KeyValuePair<string, string> attr in attributes)
{
context.Writer.WriteString($"{attr.Key}:{attr.Value}");
}
context.Writer.WriteEndArray();
}
}
public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo)
{
string elementName = null;
var serializer = BsonSerializer.LookupSerializer(typeof(string));
var nominalType = typeof(string);
serializationInfo = new BsonSerializationInfo(elementName, serializer, nominalType);
return true;
}
}
Все сериализации элементов работает, однако при попытке запросить данные через драйвер и попытаться сделать что-то эквивалентное этому db.Product.find({ Attributes : { $in : [ "Colour:Blue" ] } })
Я получаю сообщение об ошибке.
Исходная ошибка указала, что сериализатор должен быть IBsonArraySerializer
, теперь это тот случай, когда мне нужно реализовать метод TryGetItemSerializationInfo
.
На основании приведенного выше примера, что должен сделать этот метод и установить его в качестве выходного?
Я попытался найти строковый сериализатор и использовать его, но он дает сообщение об ошибке «Невозможно наложить объект типа« System.Char »на тип« System.String ». Попытка сериализатора символов не дает ошибки, но не возвращает никаких результатов. Глядя в журналы для MongoDb, похоже, указывает, что поиск был преобразован символом по символам в целые числа, а затем был просмотрен.
Код для заявления фильтра также ниже
Database.GetCollection<Product>("Product").Find(Builders<Product>.Filter.AnyIn("Attributes", "Colour:Blue")).ToListAsync()
Большое спасибо Craig, который отлично работает с использованием массива – rrrr