Я хотел бы иметь возможность обновлять пару ключ / значение в документе в коллекции без учета _id.Этот SO-ответ , по-видимому, предоставляет способ сделать то, что я хочу, но требует сосредоточенности на ключе _id.
По сути, что я могу сделать, чтобы получить мой код, как показано ниже, чтобы работать без добавления атрибута [BsonIgnoreExtraElements]
в класс?
Основываясь на коде, который я покажу ниже, я думаю, что я близок, и у меня do есть возможностьОбходной путь, используя атрибут, который я также покажу.Тем не менее, я хотел бы сделать это без украшения классов с какими-либо атрибутами, если это возможно.
Почему нет _id?Лично я считаю, что поле _id просто мешает.Он не является частью какого-либо из моих классов, и MongoDB не является реляционным, поэтому я просто не использую его.Я свободно признаю, что, возможно, я полностью упускаю намерение и идею использования поля _id, но я просто не вижу необходимости в этом в MongoDB.Тем не менее, если возможно, я бы хотел сосредоточиться на работе без акцента на поле _id.
С учетом сказанного у меня есть методы для извлечения одного документа или всей коллекции вместе со вставкой одного документа илився коллекция, как правило, без учета поля _id.
Я обнаружил, что ключом к игнорированию _id в "select" является использование проекции.Я не очень хорошо знаком с драйвером, но вот строки кода, которые делают магию:
public const string ELEMENT_ID = "_id";
ProjectionDefinition<T> projection = Builders<T>.Projection.Exclude(ELEMENT_ID);
IFindFluent<T, T> found = mongoCollection.Find(bsonDocument).Project<T>(projection);
Для справочной информации, вот метод поиска, игнорирующий _id:
public T GetSingle<T>(string property, string value) where T : class, new()
{
T tObject = null;
try
{
if (MongoContext.MongoClient != null && MongoContext.MongoDatabase != null)
{
string className = typeof(T).ToString();
int lastPeriod = className.LastIndexOf('.');
int length = className.Length - lastPeriod;
className = className.Substring(lastPeriod + 1, length - 1);
if (!string.IsNullOrEmpty(className))
{
IMongoCollection<T> mongoCollection = MongoContext.MongoDatabase.GetCollection<T>(className);
if (mongoCollection != null)
{
BsonDocument bsonDocument = new BsonDocument();
ProjectionDefinition<T> projection = Builders<T>.Projection.Exclude(ELEMENT_ID);
PropertyInfo[] propertyInfo = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
if (propertyInfo != null && propertyInfo.Length > 0)
{
IEnumerable<PropertyInfo> piExisting = propertyInfo.Where(pi => pi.Name.Equals(property, StringComparison.CurrentCultureIgnoreCase));
if (piExisting != null && piExisting.Any())
{
BsonValue bsonValue = BsonValue.Create(value);
BsonElement bsonElement = new BsonElement(property, bsonValue);
if (bsonElement != null)
{
bsonDocument.Add(bsonElement);
}
IFindFluent<T, T> found = mongoCollection.Find(bsonDocument).Project<T>(projection);
if (found != null)
{
tObject = found.FirstOrDefault<T>();
}
}
}
}
}
}
}
catch (Exception ex)
{
Logger.WriteToLog(Logger.LoggerMessage(ex));
}
return tObject;
}
Похож на другой ответ SO , я пытался использовать FindOneAndUpdate
, но получаю следующую ошибку:
Элемент '_id' не совпадаетлюбое поле или свойство класса ClassThingy.Suffix.
Если бы я мог как-то применить Проекцию к FindOneAndUpdate
, я думаю, что это могло бы решить мою проблему, но я не смог найти способчтобы сделать это приложение.
Вот мой код:
public T UpdateSingle<T>(T item, string property, object originalValue, object newValue) where T : class, new()
{
string className = string.Empty;
T updatedDocument = null;
try
{
if (MongoContext.MongoClient != null && MongoContext.MongoDatabase != null)
{
className = ClassUtility.GetClassNameFromObject<T>(item);
if (!string.IsNullOrEmpty(className))
{
IMongoCollection<T> mongoCollection = MongoContext.MongoDatabase.GetCollection<T>(className);
if (mongoCollection != null)
{
BsonDocument bsonDocument = new BsonDocument();
ProjectionDefinition<T> projection = Builders<T>.Projection.Exclude(ELEMENT_ID);
PropertyInfo[] propertyInfo = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public);
if (propertyInfo != null && propertyInfo.Length > 0)
{
IEnumerable<PropertyInfo> piExisting = propertyInfo.Where(pi => pi.Name.Equals(property, StringComparison.CurrentCultureIgnoreCase));
if (piExisting != null && piExisting.Any())
{
BsonValue bsonValue = BsonValue.Create(originalValue);
BsonElement bsonElement = new BsonElement(property, bsonValue);
if (bsonElement != null)
{
bsonDocument.Add(bsonElement);
}
IFindFluent<T, T> found = mongoCollection.Find(bsonDocument).Project<T>(projection);
if (found != null)
{
FilterDefinition<T> filterDefinition = Builders<T>.Filter.Eq(property, originalValue);
UpdateDefinition<T> updateDefinition = Builders<T>.Update.Set(property, newValue);
updatedDocument = mongoCollection.FindOneAndUpdate<T>(filterDefinition, updateDefinition);
}
}
}
}
}
}
}
catch (Exception ex)
{
Logger.WriteToLog(Logger.LoggerMessage(ex));
}
return updatedDocument;
}
Интересно, что метод FindOneAndUpdate
действительно выглядит успешным, а коллекция "Суффикс" действительно получаетмодифицирована.Кроме того, возвращение не содержит модификации.Вместо этого это «оригинал» (когда я использую обходной путь, как показано ниже).
Дополнительная информация:
Класс суффикса:
public class Suffix
{
public string Code { get; set; }
public string Description { get; set; }
}
Suffix suffix = new Suffix();
MongoRepository.MongoRepository mongoRepository = new MongoRepository.MongoRepository("MyDataBase");
mongoRepository.UpdateSingle<Suffix>(suffix, "Description", "Jr", "Junior");
Обходной путь:
[BsonIgnoreExtraElements]
public class Suffix
{
public string Code { get; set; }
public string Description { get; set; }
}
Но, скорее, не используйте атрибут, если это вообще возможно.