考虑以下课程
public class Something
{
public ObjectId Id;
public DateTime DbUpdatedAt;
public string AnotherProperty;
public int SomeIntProp;
}
我通常会使用以下代码进行部分更新
var obj = ... // an instance of Something
var update = new UpdateBuilder<Something>();
update.Set(x => x.DbUpdatedAt, DateTime.UtcNow);
...
/// later on,
// database is an instance of MongoDatabase
database.GetCollection("CollectionName")
.Update(Query<Something>.Eq(x => x.Id, something.Id), update);
问题是,我不知道有任何方法可以检查update
是否已配置为DbUpdatedAt
设置值。
如果我盲目地尝试为DbUpdatedAt
设置新值,我会收到错误。
...
/// later on,
update.Set(x => x.DbUpdatedAt, DateTime.UtcNow.AddHours(1)); // this throws a Duplicate element name error
// database is an instance of MongoDatabase
database.GetCollection("CollectionName")
.Update(Query<Something>.Eq(x => x.Id, something.Id), update);
我明白为什么会发生错误。我需要一种方法,
答案 0 :(得分:2)
当前实现的UpdateBuilder考虑尝试将同一个字段设置为两个不同的值(尽管我希望抛出的异常更清楚......)。
期望两次调用相同字段的Set会简单地用第二个字段覆盖第一个字段并不是没有道理的,但这不是它当前的工作方式。如果您觉得它应该以这种方式工作,请提交一份建议更改的JIRA票。
作为一种变通方法,您可以在UpdateBuilder上定义一个行为符合您希望的扩展方法。它可能看起来像这样:
public static UpdateBuilder<TDocument> SetWithOverride<TDocument, TField>(this UpdateBuilder<TDocument> update, Expression<Func<TDocument, TField>> memberExpression, TField value)
{
var set = Update<TDocument>.Set(memberExpression, value).ToBsonDocument();
var combined = update.ToBsonDocument();
if (combined.Contains("$set"))
{
var element = set[0].AsBsonDocument.GetElement(0);
combined["$set"][element.Name] = element.Value;
}
else
{
combined.Merge(set);
}
return Update<TDocument>.Combine(combined.Elements.Select(e => new UpdateDocument(e)));
}
以下是一些显示正在使用的示例代码:
var update = Update<C>.Set(c => c.X, 1).Set(c => c.Y, 2);
update = update.SetWithOverride(c => c.Y, 3);
答案 1 :(得分:0)
来自the manuals:
使用$ set运算符将字段的值替换为指定的值。如果该字段不存在,$ set运算符将添加具有指定值的字段。
根据您的说明,您不应该收到任何重复的密钥错误,除非您已DbUpdatedAt
部分unique index或部分错误。
我认为更常见的错误是插入文档而不是更新文档(使用C#驱动程序很容易)但如果使用Mongo的查询构建器进行更新,则不会发生这种情况,正如你似乎在做的那样。
总而言之,你得到的错误没有意义。你确定没有其他事情导致这个错误吗?