使用忽略 _id 的驱动程序更新文档
Document Update Using Driver Ignoring _id
我希望能够更新集合中文档中的 key/value 对,而不考虑 _id。 似乎提供了一种方法来做我想做的事,但它需要关注 _id 键。
基本上,我可以做些什么来让我的代码(如下所示)在不将 [BsonIgnoreExtraElements]
属性添加到 class 的情况下工作?
根据我将在下面显示的代码,我认为我已经接近了,并且我 确实 有一个可能的解决方法,使用该属性,我也会展示。但是,如果可能的话,我想在不使用任何属性装饰 classes 的情况下执行此操作。
为什么没有_id?就个人而言,我发现 _id 字段只是妨碍。它不属于我的任何 classes,并且 MongoDB 不是关系型的,所以我根本不使用它。我坦率地承认,我可能完全忽略了使用 _id 字段背后的意图和想法,但我根本看不到 MongoDB 中需要它。不过,如果可能的话,我想专注于工作而不关注 _id 字段。
话虽如此,我有检索单个文档或整个集合以及插入单个文档或整个集合的方法,一般而言,不考虑 _id 字段。
我发现忽略 "select" 中的 _id 的关键是使用投影。我对驱动程序不是很熟悉,但这里是神奇的代码行:
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;
}
与另一个 类似,我尝试使用 FindOneAndUpdate
,但收到以下错误:
Element '_id' does not match any field or property of class
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
方法实际上看起来成功了,而 "Suffix" 集合实际上得到了修改。此外,return 不包含修改。相反,它是 "original"(当我使用如下所示的解决方法时)。
更多信息:
后缀Class:
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; }
}
但是,如果可能的话,最好不要使用该属性。
你在这里遗漏的一件事是 .FindOneAndUpdate()
方法的第三个参数,它是类型 FindOneAndUpdateOptions<T,T>
。这是您可以定义是否要获取文档 After
或 Before
修改的地方。 Before
是默认值 此外,您可以指定投影并排除 _id
属性。尝试:
FilterDefinition<T> filterDefinition = Builders<T>.Filter.Eq(property, originalValue);
UpdateDefinition<T> updateDefinition = Builders<T>.Update.Set(property, newValue);
ProjectionDefinition<T, T> projection = Builders<T>.Projection.Exclude("_id");
var options = new FindOneAndUpdateOptions<T>()
{
Projection = projection,
ReturnDocument = ReturnDocument.After
};
updatedDocument = mongoCollection.FindOneAndUpdate<T>(filterDefinition, updateDefinition, options);
我希望能够更新集合中文档中的 key/value 对,而不考虑 _id。
基本上,我可以做些什么来让我的代码(如下所示)在不将 [BsonIgnoreExtraElements]
属性添加到 class 的情况下工作?
根据我将在下面显示的代码,我认为我已经接近了,并且我 确实 有一个可能的解决方法,使用该属性,我也会展示。但是,如果可能的话,我想在不使用任何属性装饰 classes 的情况下执行此操作。
为什么没有_id?就个人而言,我发现 _id 字段只是妨碍。它不属于我的任何 classes,并且 MongoDB 不是关系型的,所以我根本不使用它。我坦率地承认,我可能完全忽略了使用 _id 字段背后的意图和想法,但我根本看不到 MongoDB 中需要它。不过,如果可能的话,我想专注于工作而不关注 _id 字段。
话虽如此,我有检索单个文档或整个集合以及插入单个文档或整个集合的方法,一般而言,不考虑 _id 字段。
我发现忽略 "select" 中的 _id 的关键是使用投影。我对驱动程序不是很熟悉,但这里是神奇的代码行:
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;
}
与另一个 FindOneAndUpdate
,但收到以下错误:
Element '_id' does not match any field or property of class 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
方法实际上看起来成功了,而 "Suffix" 集合实际上得到了修改。此外,return 不包含修改。相反,它是 "original"(当我使用如下所示的解决方法时)。
更多信息:
后缀Class:
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; }
}
但是,如果可能的话,最好不要使用该属性。
你在这里遗漏的一件事是 .FindOneAndUpdate()
方法的第三个参数,它是类型 FindOneAndUpdateOptions<T,T>
。这是您可以定义是否要获取文档 After
或 Before
修改的地方。 Before
是默认值 此外,您可以指定投影并排除 _id
属性。尝试:
FilterDefinition<T> filterDefinition = Builders<T>.Filter.Eq(property, originalValue);
UpdateDefinition<T> updateDefinition = Builders<T>.Update.Set(property, newValue);
ProjectionDefinition<T, T> projection = Builders<T>.Projection.Exclude("_id");
var options = new FindOneAndUpdateOptions<T>()
{
Projection = projection,
ReturnDocument = ReturnDocument.After
};
updatedDocument = mongoCollection.FindOneAndUpdate<T>(filterDefinition, updateDefinition, options);