在 web api 的补丁操作中更新 mongo 的正确方法
Proper way to update mongo in patch action in web api
我想在 web 中实施补丁操作 api,
考虑我在 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 中,我收到此对象作为输入。客户端可以编辑这些字段中的一个或多个,如果 属性 为 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);
*顺便说一句,如果有更好的解决方案,我们将不胜感激
你可能会这样做。
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),一般来说我会选择第二种方法,仅在性能要求非常严格或网络带宽较低的情况下才回退到第一种方法。
我想在 web 中实施补丁操作 api, 考虑我在 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 中,我收到此对象作为输入。客户端可以编辑这些字段中的一个或多个,如果 属性 为 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);
*顺便说一句,如果有更好的解决方案,我们将不胜感激
你可能会这样做。
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),一般来说我会选择第二种方法,仅在性能要求非常严格或网络带宽较低的情况下才回退到第一种方法。