2014-01-20 22 views
2

考慮下面的類如何構建UpdateBuilder

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); 

我明白爲什麼錯誤發生。我需要一種方法,

  1. 檢測有重複的關鍵場景,
  2. 更換舊密鑰,用新密鑰,值對值對。

回答

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); 
+0

謝謝。這很好。爲了在任何情況下都能正常工作,我總是必須使用SetWithOverride(因爲我不確定另一個函數是否已經調用了set)。考慮到這一點,該功能是否有任何性能問題?代碼將兩個更新語句轉換爲bson文檔,然後返回到更新語句。所有這些反序列化/序列化都會對許多調用產生影響嗎? –

+0

另外,我創建了一個JIRA問題(https://jira.mongodb.org/browse/CSHARP-902)。希望,它會很快實施:) –

0

the manuals

使用$集合運算符的一個字段的值替換爲指定的值。如果該字段不存在,$ set操作符將添加具有指定值的字段。

從你的描述,你不應該得到任何重複鍵錯誤,除非你已經取得了一些unique index什麼DbUpdatedAt部分。

我認爲一個更常見的錯誤是插入一個文檔而不是更新一個(這很容易使用C#驅動程序),但如果您使用Mongo的查詢構建器進行更新,則不會發生這種情況,因爲你似乎在做。

總而言之,你得到的錯誤沒有意義。你確定沒有其他事情會導致這個錯誤嗎?

+0

感謝您的回答。但是,我面臨的問題是不同的。代碼編寫的方式是:{$ set:{'DbUpdated':,'DbUpdated':<另一個日期值>}}'...文檔具有相同的結果鍵'DbUpdated'兩次,這是無效的。 @RobertStam提出了一種解決方法,它檢查文檔是否已經包含密鑰並相應地處理它。 –