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をそのままにしておく必要がありますが、メンバーのタイトルとコンテンツを更新する必要があります。

コメントアウトされたコードは機能しますが、最も効率的ではないようです。FindOneを呼び出すと、それはmongodbへの1回の旅行です。次に、else句に移動すると、別のクエリと更新操作が実行されるため、mongodbにさらに2回移動します。

私が達成しようとしていることを行うためのより効率的な方法は何ですか?

4

2 に答える 2

2

As mentioned in the linked SO answer, for upserts to work, you need to update the entire document, not just a few properties.

Personally I would separate the Create and Edit into separate MVC actions. SRP. Creating a Thingy has different considerations from updating it.

If you still want to do an upsert instead of separate insert/update calls, you will need to use the following code:

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

The question now becomes, how do we ensure the thing has the appropriate values for both cases, ie insert as well as update.

My assumption is (based on your code model binding to a Thingy instance), your view is sending back all fields (including UUID and TimeCreated). Which implies, in case of an update, the view already has the values pre-populated for UUID and TimeCreated. So in the case of a Thingy being updated, the thing object has the latest values.

Now in case of an create, when the view is rendered, you could store DateTime.MinValue for the TimeCreated field. In your Create MVC action, you could check if TimeCreated is DateTime.MinValue, then set it to current time and also store a new value for UUID.

This way, in the case of a insert as well, the thing has the latest values. We can thus safely do an Upsert.

于 2012-09-17T16:13:05.283 に答える
0

コントローラーからMongoのアップサートを行うとき、私はこのアプローチを取ります

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 に答える