在web api中更新补丁动作中mongo的正确方法

时间:2017-12-28 18:55:50

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

我想在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中我收到此对象作为输入。客户端可以编辑这些字段中的一个或多个,如果property为null,则表示该值应保留为之前的值。 我想做的是在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);

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

1 个答案:

答案 0 :(得分: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);

第二种方法有以下Pro和Cons。

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

缺点

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

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