2

我有以下 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,但必须更新成员 Title 和 Content。

注释掉的代码有效,但似乎不是最有效的。当它调用 FindOne 时,即是对 mongodb 的一次访问。然后,如果它转到 else 子句,它会执行另一个查询和一个更新操作,因此又是 2 次到 mongodb 的行程。

什么是更有效的方法来完成我想要完成的事情?

4

2 回答 2

2

如链接的 SO 答案中所述,要使 upserts 起作用,您需要更新整个文档,而不仅仅是几个属性。

就我个人而言,我会将CreateandEdit分成单独的 MVC 操作。建议零售价。创建一个Thingy与更新它有不同的考虑。

如果您仍想执行 upsert 而不是单独的插入/更新调用,则需要使用以下代码:

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

现在的问题变成了,我们如何确保这thing两种情况都具有适当的值,即插入和更新。

我的假设是(基于您的代码模型绑定到Thingy实例),您的视图正在发回所有字段(包括UUIDand TimeCreated)。这意味着,在更新的情况下,视图已经预先填充了UUID和的值TimeCreated。因此,在Thingy更新的情况下,thing对象具有最新的值。

现在,在创建的情况下,当呈现视图时,您可以存储DateTime.MinValueTimeCreated字段。在您的CreateMVC 操作中,您可以检查是否TimeCreatedDateTime.MinValue,然后将其设置为当前时间并为UUID.

这样,在插入的情况下,thing也具有最新值。因此,我们可以安全地进行 Upsert。

于 2012-09-17T16:13:05.283 回答
0

我在从控制器为 Mongo 做 upserts 时采用这种方法

public ActionResult Create(Thingy model)
{
    var thing = _collection.FindOneAs<Thingy>(Query.EQ("UUID", model.UUID));
    if(thing == null)
    {
       thing = new Thingy{
                         TimeCreated = DateTime.Now,
                         UUID = System.Guid.NewGuid().ToString(),
                         Id = ObjectId.GenerateNewId()
                        }
    }
    else 
    {
       thing.Content = model.Content;
       //other updates here
    }

    _collection.Save<Thingy>(thing);
    return View();
}
于 2014-06-06T21:08:59.647 回答