我有一些类型User
的poco,我担心它的属性将来会改变。我有一个带Users
集合的MongoDB来存储数据。它没有唯一性约束,我无法创建一个不幸的。我的应用程序从第三方存档源导入一堆旧用户,我希望能够将这些用户写入Mongo,但我不希望重复,也不希望在Match上替换用户数据,因为Mongo中的数据是实际的。基本上,我们可以通过匹配像a.Username == b.Username && a.Email == b.Email
这样的过滤器或者类似的东西来定义用户重复,我不希望它与这个问题相关,我们可以说有一种方法可以判断用户a和b是否相同。
所以看起来我在这里唯一的选择就是使用upsert update和setoninsert。在c driver中有一个方法Builders<User>.Update.SetOnInsert<TField>(Expression<User,TField>, TField)
,但我必须多次调用它才能枚举所有属性。如果这些属性将来要改变,就必须有人更新这个方法,我不喜欢它。
有办法绕过这个问题吗?可能通过使用reflecion和PropertyInfo
或者直接使用BsonDocument
来实现?或者我漏掉了什么东西还有更简单的方法?提前谢谢。
最佳答案
好吧,其实没那么难:
var updates = new List<WriteModel<User>>();
foreach (User appUser in users)
{
FilterDefinition<User> filter = Builders<User>.Filter.Eq(x => x.Username, appUser.Username) & ...
var bsonDoc = appUser.ToBsonDocument();
UpdateDefinition<User> updateDefinition = new UpdateDefinitionBuilder<User>().Unset("______"); // HACK: I found no other way to create an empty update definition
foreach (var element in bsonDoc.Elements)
{
if (element.Name == "_id" || element.Value == BsonNull.Value)
continue;
updateDefinition = updateDefinition.SetOnInsert(element.Name, element.Value);
}
UpdateOneModel<User> update = new UpdateOneModel<User>(filter, updateDefinition) { IsUpsert = true };
updates.Add(update);
}
MongoConnectionHelper.Database.GetCollection<User>("Users").BulkWrite(updates);