2013-08-12 2 views
2

Я пытаюсь использовать NodaTime в своем приложении. Приложение сохраняет данные в базе данных mongodb. Рассмотрим следующий классКак пользовательский сериализатор влияет на поиск?

public class SomeType 
{ 
    public ObjectId Id { get; set; } 
    public Instant Instant { get; set; } 
    [BsonDateTimeOptions(Kind = DateTimeKind.Local)] 
    public DateTime DateTime { get; set; } 
    [BsonDateTimeOptions(Kind = DateTimeKind.Utc)] 
    public DateTime DateTimeUtc { get; set; } 
// public ZonedDateTime ZonedDateTime { get; set; } 
// public LocalDateTime LocalDateTime { get; set; } 
} 

Без добавления пользовательского сериалайзер, то Instant свойство класса не откладываются в БД. Чтение документа из db также не выполняется.

public class InstantBsonSerializer : BsonBaseSerializer 
{ 
    public override object Deserialize(BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options) 
    { 
     var ticks = bsonReader.ReadInt64(); 
     return new Instant(ticks); 
    } 

    public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options) 
    { 
     var ticks = bsonReader.ReadInt64(); 
     return new Instant(ticks); 
    } 

    public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options) 
    { 
     var instant = (Instant) value; 
     bsonWriter.WriteInt64(instant.Ticks); 
    } 
} 

Я создал вышеупомянутый сериализатор и зарегистрировал его должным образом. Теперь я могу сохранять и извлекать экземпляры моего класса с правильным значением, установленным для Instant.

Мой вопрос в том, как обрабатывать дескриптор C# с помощью linq?

var list = mongoDatabase.GetCollection<SomeType>("SomeType") 
        .AsQueryable<SomeType>() 
        .Where(x => x.Instant < Instant.FromDateTimeUtc(dateTime.ToUniversalTime())) 
        .ToList(); 
Console.WriteLine(list.Count); 

Я получаю правильный список документов. Я пытаюсь понять, КАК mongodb получает эти данные. Он сначала загружает ВСЕ данные, десериализует их правильно, а затем фильтрует? Или он сериализует значение Instant значения предложения where и использует сериализованное значение для фильтрации всех документов, загрузки совпадающих и затем десериализации?

Я попытался просмотреть запрос, зарегистрированный профилировщиком mongodb, но его, похоже, ничего не записывает. Я установил уровень профилирования равным 2.

В случае Instant сериализованное значение - long. Но в случае ZonedDateTime сериализованное значение будет документом с двумя свойствами. Как будет искать работу в этом случае?

Edit:

я смог профилирование работать. Следующий C# запрос,

mongoDatabase.GetCollection<SomeType>("SomeTypeCollection") 
      .AsQueryable<SomeType>() 
      .Where(x => x.Instant < Instant.FromDateTimeUtc(DateTime.UtcNow)) 
      .ToList(); 

приводит к следующему MongoDB запроса

{ "Instant": { $lt: 13781017828460782 }} 

Значение, C# драйвер сериализует мой Instant объект и использует сериализированное значение для фильтрации результатов в самой БД.

ответ

1

Драйвер преобразует ваш запрос linq в запрос mongodb и фильтрует результаты перед их десериализацией. Запрос не будет работать, пока вы не вызовете ToList()

Вот операторы, которые поддерживаются: http://docs.mongodb.org/ecosystem/tutorial/use-linq-queries-with-csharp-driver/

обычая deserialiser не войдет в игру, пока водитель не начнет строить граф объекта из возвращенных данных.

Обычно вам не нужен специальный сериализатор для классов с простыми типами или где вы не выполняете дополнительную работу при чтении и записи документов.

Если вы хотите контролировать то, что было сериализовано, то есть, если по существу ваш класс содержит одно время, почему бы не сделать так, чтобы штамп даты и времени UTC сохранялся и использовал BsonIgnore для других свойств.

+0

Но предложение фильтра использует класс, для которого требуется собственный сериализатор. Как mongodb способен создать из него манго-запрос? Если бы я написал его как манго-запрос, я бы передал «bson object» в качестве значения для оператора '$ lt'. Но как драйвер C# представляет мой пользовательский сериализованный класс как объект bson? –

+0

Из того, что я понимаю, драйвер будет использовать отражение, чтобы установить имена атрибутов для компиляции запроса так: var res = mongodb.GetCollection («MyColl»). AsQueryable () .Where (x => x.Prop == 123) 'будет компилировать запрос' {Prop: {$ eq: 123}} 'или' {Prop: 123} '- с помощью атрибута BsonElement можно управлять именем атрибута при сериализации и запросе. Как только запрос будет возвращен, драйвер будет десериализовать BsonDocument в объект. Карта классов по умолчанию, используемая для этого класса, будет использоваться, если вы используете сериализатор по умолчанию. – sambomartin

+0

стоит отметить, что вы можете запросить базу данных, проходящую в BsonDocument для запроса, возвращая курсор, который вы итерации возвращаете BsonDocument для каждого результата. Индивидуально каждый может быть десериализован в объект C# POCO. Если есть специальный сериализатор, зарегистрированный для определенного типа, он будет использоваться для гидратации объекта. – sambomartin

Смежные вопросы