Настройка модели с помощью атрибутов

Последнее обновление: 25.10.2022

Используя атрибуты, мы можем управлять настройкой классов моделей C# и их сериализацией в документы mongodb. Все классы атрибутов расположены в пространстве имен MongoDB.Bson.Serialization.Attributes. Рассмотрим, как мы их можем использовать.

Установка Id

Каждый объект в базе данных имеет поле _id, которое выполняет роль уникального идентификатора объекта. Используя атрибут BsonId мы можем явно установить свойство, которое будет выполнять роль идентификатора:

using MongoDB.Bson.Serialization.Attributes;

class Person
{
    [BsonId]
    public int PersonId { get; set; }
    public string Name { get; set; } = "";
}

Хотя в данном случае свойство называется PersonId и имеет тип int, при создании документа данное свойство будет представлять в документе поле _id

Исключение свойств

Атрибут BsonIgnore позволяет не учитывать свойство при сериализации объекта в документ. Например:

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

Person tom = new Person { Name = "Tom", Email = "tom@somemail.com" };
Console.WriteLine(tom.ToBsonDocument()); // { "Name" : "Tom" }

class Person
{
    public string Name { get; set; } = "";
    [BsonIgnore]
    public string Email { get; set; } = "";
}

В примере выше исключается из сериализации в BsonDocument свойство Email.

BsonElement

По умолчанию при сериализации поля документа будут называться также, как и свойства класса C#. Атрибут BsonElement позволяет изменить название:

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

Person tom = new Person { Name = "Tom", Email = "tom@somemail.com" };
Console.WriteLine(tom.ToBsonDocument()); // { "Name" : "Tom", "Login" : "tom@somemail.com" }

class Person
{
    public string Name { get; set; } = "";
    [BsonElement("Login")]
    public string Email { get; set; } = "";
}

Здесь при сериализации в BsonDocument значение свойства Email будет передаваться полю с именем "Login".

Игнорирование значений по умолчанию

Атрибут BsonIgnoreIfNull позволяет игнорировать при сериализации свойства со значениями null. А атрибут BsonIgnoreIfDefault позволяет исключить из сериализации свойства со значениями по умолчанию. Зачем они могут пригодиться? Рассмотрим следующую ситуацию::

using MongoDB.Bson;

Person tom = new Person { Name = "Tom"};
Console.WriteLine(tom.ToBsonDocument()); // { "Name" : "Tom", "Age" : 0, "Company" : null }

class Person
{
    public string Name { get; set; } = "";
    public int Age { get; set; }
    public Company? Company { get; set; }
}
class Company
{
    public string Name { get; set; } = "";
}

В этом примере для объекта Person задается объект Company. Однако в какой-то ситуации для объекта Person данный объект может отсутствовать. Например, человек не работает ни в какой компании. Однако даже если мы не укажем компанию, такой документ все равно будет содержать данный элемент, только у него будет значение null.

Также в примере определено свойство Age, которое представляет возраст человека. Однако в каких-то ситуациях, возможно, не потребуется это свойство. Но даже если мы не указали значение для свойства Age, оно будет присутствовать в документе со значением 0 - то есть значением по умолчанию.

То есть для объекта

Person tom = new Person { Name = "Tom"};

Мы получим документ

{ "Name" : "Tom", "Age" : 0, "Company" : null }

Чтобы избежать этих проблем, используем атрибуты BsonIgnoreIfNull и BsonIgnoreIfDefault:

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

Person tom = new Person { Name = "Tom"};
Console.WriteLine(tom.ToBsonDocument()); // { "Name" : "Tom" }

class Person
{
    public string Name { get; set; } = "";
    [BsonIgnoreIfDefault]
    public int Age { get; set; }
    [BsonIgnoreIfNull]
    public Company? Company { get; set; }
}
class Company
{
    public string Name { get; set; } = "";
}

Теперь мы получим следующий документ:

{ "Name" : "Tom" }

BsonRepresentation

Еще один атрибут BsonRepresentation отвечает за представление свойства в базе данных. Например:

class Person
{
    public string Name { get; set; } = "";
	[BsonRepresentation(BsonType.String)]
    public int Age { get; set; }
}

В этом случае целочисленному свойству Age в базе данных будет соответствовать строковое поле Age из-за применения атрибута [BsonRepresentation(BsonType.String)].

BsonClassMap

Для настройки сопоставления классов C# с коллекциями MongoDB можно использовать класс BsonClassMap, который регистрирует принципы сопоставления. Например, возьмем тот же класс Person:

using MongoDB.Bson;
using MongoDB.Bson.Serialization;

BsonClassMap.RegisterClassMap<Person>(cm =>
{
    cm.AutoMap();
    cm.MapMember(p => p.Name).SetElementName("username");
});
Person tom = new Person { Name = "Tom", Age = 38};
Console.WriteLine(tom.ToBsonDocument()); // { "username" : "Tom", "Age" : 38 }

class Person
{
    public string Name { get; set; } = "";
    public int Age { get; set; }
}

С помощью метода RegisterClassMap() определяется карта сопоставления объектов Person и BsonDocument. В частности, в данном случае для свойство Name будет сопоставляться с полем username.

Стоит отметить, что регистрация маппингов должна происходить до установки соединения с сервером MongoDB. Иначе приложение будет падать с ошибкой.

Конвенции

Конвенции наряду с атрибутами и BsonClassMap представляют еще один способ определения сопоставления классов и объектов BsonDocument. Конвенции определяются в виде набора - объекта ConventionPack. Этот объект может содержать набор конвенций. Каждая конвенция представляет объект класса, производного от ConventionBase. Например, переведем все имена элементов в BsonDocument в нижний регистр:

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Conventions;

var conventionPack = new ConventionPack
{
    new CamelCaseElementNameConvention()
};
ConventionRegistry.Register("camelCase", conventionPack, t => true);
Person tom = new Person { Name = "Tom", Age = 38};
Console.WriteLine(tom.ToBsonDocument()); // { "name" : "Tom", "age" : 38 }

class Person
{
    public string Name { get; set; } = "";
    public int Age { get; set; }
}

В данном случае создается объект ConventionPack - набор конвенций, в котором по умолчанию определяется одна конвенция - CamelCaseElementNameConvention, которая переводит названия свойства в camel case - имена начинаются со строчной буквы.

Но чтобы конвенция сработала, необходимо вызвать метод ConventionRegistry.Register(), который зарегистрирует конвенцию. Первый параметр этого метода представляет название конвенции, второй - объект ConventionPack, а третий - условие, при котором применяется конвенция. Здесь в качестве условия просто установлено ключевое слово true, то есть конвенция будет применяться ко всем свойствам.

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

{ "name" : "Tom", "age" : 38 }
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850