我有以下C模型课程:

public class Thingy
{
    public ObjectId Id { get; set; }
    public string Title { get; set; }
    public DateTime TimeCreated { get; set; }
    public string Content { get; set; }
    public string UUID { get; set; }
}

以及以下asp.mvc控制器操作:
public ActionResult Create(Thingy thing)
{
    var query = Query.EQ("UUID", thing.UUID);
    var update = Update.Set("Title", thing.Title)
        .Set("Content", thing.Content);

    var t = _collection.Update(query, update, SafeMode.True);
    if (t.UpdatedExisting == false)
    {
        thing.TimeCreated = DateTime.Now;
        thing.UUID = System.Guid.NewGuid().ToString();
        _collection.Insert(thing);
    }

        /*
        var t = _collection.FindOne(query);

        if (t == null)
        {
            thing.TimeCreated = DateTime.Now;
            thing.UUID = System.Guid.NewGuid().ToString();
            _collection.Insert(thing);
        }
        else
        {
            _collection.Update(query, update);
        }
        */
        return RedirectToAction("Index", "Home");
    }

此方法执行更新或插入。如果需要插入,则必须设置uuid和timecreated成员。如果需要进行更新,则必须保留uuid和timecreated,但必须更新成员的标题和内容。
注释掉的代码可以工作,但似乎不是最有效的。当它调用findone时,这是一次mongodb之旅。然后如果它转到else子句,它将执行另一个查询和一个更新操作,这样就可以再访问mongodb两次。
做我想做的事,有什么更有效的方法?

最佳答案

正如linked so答案中提到的,要使upserts工作,您需要更新整个文档,而不仅仅是一些属性。
就我个人而言,我会将CreateEdit分离为单独的mvc操作。SRP。创建Thingy与更新它有不同的考虑因素。
如果仍要执行upsert而不是单独的插入/更新调用,则需要使用以下代码:

_collection.Update(
    Query.EQ("UUID", thing.UUID),
    Update.Replace(thing),
    UpsertFlags.Upsert
);

现在的问题是,我们如何确保thing对于这两种情况都有适当的值,即插入和更新。
我的假设是(基于您绑定到Thingy实例的代码模型),您的视图将发送回所有字段(包括UUIDTimeCreated)。这意味着,在更新的情况下,视图已经预先填充了UUIDTimeCreated的值。因此,在更新Thingy的情况下,thing对象具有最新的值。
现在,在创建的情况下,当呈现视图时,可以为DateTime.MinValue字段存储TimeCreated。在Createmvc操作中,您可以检查TimeCreated是否DateTime.MinValue,然后将其设置为当前时间,并为UUID存储一个新值。
这样,在插入的情况下,thing也有最新的值。这样我们就可以安全地进行一次升级。

关于c# - 在mongodb中执行高效的upsert,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12460005/

10-09 18:48