【问题标题】:Proper way to update mongo in patch action in web api在 web api 的补丁操作中更新 mongo 的正确方法
【发布时间】:2017-12-28 18:55:50
【问题描述】:

我想在 web api 中实现 Patch 动作, 考虑我在 mongo 中有这样的客户集合:

public string Id{ get; set; }
public string Name{ get; set; }
public string Family{ get; set; }
public string Sex{ get; set; }
public string City{ get; set; }
public string CustomerId{ get; set; }

在我的 api 中,我收到这个对象作为输入。客户端可以编辑这些字段中的一个或多个,如果属性为空,则表示该值应保持以前的值。 我想做的是在 mongo 查询中我想说如果属性为 null 不要更新考虑这个:

var filter = Builders<Customer>.Filter.Eq(s => s.CustomerId, CustomerId);
var builder = Builders<Customer>.Update.Set(???)//set only not null values
mongo.UpdateOne(filter, builder);

*顺便说一下,任何更好的解决方案都值得赞赏

【问题讨论】:

    标签: c# mongodb asp.net-web-api http-patch


    【解决方案1】:

    你可能会做这样的事情。

    var filter = Builders<Customer>.Filter
        .Eq(s => s.CustomerId, customer.CustomerId); //perhaps requires an index on CustomerId field
    var update = Builders<Customer>.Update
        .Set(p => p.CustomerId, customer.CustomerId);
    if (!string.IsNullOrWhiteSpace(customer.City))
        update = update.Set(p => p.City, customer.City);
    if (!string.IsNullOrWhiteSpace(customer.Name))
        update = update.Set(p => p.Name, customer.Name);
    if (!string.IsNullOrWhiteSpace(customer.Family))
        update = update.Set(p => p.Family, customer.Family);
    if (!string.IsNullOrWhiteSpace(customer.Sex))
        update = update.Set(p => p.Sex, customer.Sex);
    
    customers.UpdateOne(filter, update);
    

    另一种方法可能会将您的客户实体视为一个整体(面向文档的数据库鼓励这种方法),因此始终完全更新实体并避免细粒度更新(在 R-DBMS 的情况下更有可能)。在这种情况下,你可能会写这样的东西。

    var customerFromDb = customers
        .Find(p => p.CustomerId == customer.CustomerId)
        .Single();
    
    if (!string.IsNullOrWhiteSpace(customer.City))
        customerFromDb.City = customer.City;
    if (!string.IsNullOrWhiteSpace(customer.Name))
        customerFromDb.Name = customer.Name;
    if (!string.IsNullOrWhiteSpace(customer.Family))
        customerFromDb.Family = customer.Family;
    if (!string.IsNullOrWhiteSpace(customer.Sex))
        customerFromDb.Sex = customer.Sex;
    
    customers.ReplaceOne(p => p.CustomerId == customer.CustomerId, customerFromDb);
    

    第二种方法有以下优点和缺点。

    专业版

    • 更新发生在域层(可能通过非常合适的方法),从而允许执行所有域规则并防止脏数据进入数据库;因此它更面向对象

    缺点

    • 这种方法需要对数据库进行两次点击(一次用于读取,一次用于更新);
    • 如果您的实体很大,网络必须传输比严格需要更多的数据。

    考虑到过早的优化是编程中万恶之源(或至少是大部分) (here),一般来说我会选择第二种方法,回退到第一个仅在性能要求非常严格或网络带宽较低的情况下使用。

    【讨论】:

    • 这段代码背后的原因是什么:var update = Builders.Update .Set(p => p.CustomerId, customer.CustomerId);因为我们不想更新这个,有没有更好的方法来避免这个更新?
    • 它允许update 变量保存一个定义的UpdateDefinition&lt;Customer&gt; 以传递给UpdateOne() 方法,即使没有请求更新(即如果所有接收到的属性都为空)。或者,您可以测试是否需要触发更新。但这需要对数据结构进行全面检查(非常难以维护),并且可能是过早的优化。
    猜你喜欢
    • 2011-08-19
    • 2014-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多