Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MongoDB C#使用Guid插入_C#_Mongodb_Mongodb .net Driver - Fatal编程技术网

MongoDB C#使用Guid插入

MongoDB C#使用Guid插入,c#,mongodb,mongodb-.net-driver,C#,Mongodb,Mongodb .net Driver,当尝试在Mongo中执行upsert操作时,我希望它为ID而不是对象ID生成GUID。在这种情况下,我检查以确保具有特定属性的对象不存在,并在更新发生时实际引发异常 下面是类定义的存根: 公共类事件 { [BsonId(IdGenerator=typeof(GuidGenerator))] [BsonRepresentation(BsonType.String)] [BsonIgnoreIfDefault] 公共Guid Id{get;set;} //…更多的财产和垃圾 } 下面是我们执行up

当尝试在Mongo中执行upsert操作时,我希望它为ID而不是对象ID生成GUID。在这种情况下,我检查以确保具有特定属性的对象不存在,并在更新发生时实际引发异常

下面是类定义的存根:

公共类事件
{
[BsonId(IdGenerator=typeof(GuidGenerator))]
[BsonRepresentation(BsonType.String)]
[BsonIgnoreIfDefault]
公共Guid Id{get;set;}
//…更多的财产和垃圾
}
下面是我们执行upsert操作的方式:

//查询以查看是否有任何挂起的操作
var-keyMatchQuery=Query.In(r=>r.Key,keyList);
var statusMatchQuery=Query.EQ(r=>r.Status,“待定”);
var query=query.And(keyMatchQuery,statusMatchQuery);
var updateQuery=new UpdateBuilder();
var bson=request.ToBsonDocument();
foreach(bson中的var项目)
{
SetOnInsert(item.Name,item.Value);
}
变量字段=字段。包括(req=>req.Id);
var args=new FindAndModifyArgs()
{
字段=字段,
Query=Query,
Update=updateQuery,
Upsert=true,
VersionReturned=FindAndModifyDocumentVersion.Modified
};
//向上插入
var result=Collection.FindAndModify(args);
这样做会将ID生成为ObjectID而不是GUID

首先执行.FindOne,如果失败,则执行直接插入,我完全可以通过两步操作获得所需的行为:

var existingItem=Collection.FindOneAs(查询);
如果(existingItem!=null)
{
抛出新的PendingException(string.Format(“事件已挂起:id={0}”,existingItem.id));
}
var result=Collection.Insert(mongoRequest);
在这种情况下,它会正确设置新项的GUID,但操作是非原子的。我正在寻找一种在驱动程序级别设置默认ID生成机制的方法,并认为这可以做到:

BsonSerializer.RegisterIdGenerator(typeof(Guid), GuidGenerator.Instance);
…但是没有用,我假设这是因为对于upsert,不能包含ID字段,因此没有发生序列化,Mongo正在完成所有工作。我还研究了实现一个约定,但这没有意义,因为有单独的生成机制来处理这个问题。我是否应该寻找一种不同的方法来解决这个问题,或者我只是遗漏了什么


我确实意识到GUI在Mongo中并不总是理想的,但由于与另一个系统的兼容性,我们正在探索使用它们。

您似乎在遵循这一点,但可能会以某种方式绕过“upserts”。一般的问题似乎是,操作实际上不知道它实际处理的是哪个“类”,也无法知道它需要调用自定义Id生成器

您为
\u id
字段传递给MongoDB的任何值都将始终得到尊重,而不是生成默认的ObjectID。因此,如果该字段包含在语句的更新“文档”部分,则将使用该字段

当期望“upsert”行为时,最安全的方法可能是使用修饰符。此处指定的任何内容只有在相关“upsert”操作发生插入时才会设置。因此,一般而言:

db.collection.update(
{“某物”:“匹配”}
{
//仅在插入时
“$setOnInsert”:{
“_id”:123
},
//始终在更新时应用
“$set”:{
“其他字段”:“值”
}
},
{upsert:true}
)
因此,当找到匹配的“查询”条件时,
$set
(或其他有效的更新运算符)中的任何内容都将始终“更新”。当由于不匹配而实际发生“插入”时,将应用这些字段。当然,查询部分中用于“匹配”的任何文字条件也会被设置,以便将来的“upserts”将发出“update”

因此,只要您以这种方式构建“更新”BSON文档以包含新生成的GUID,那么您将始终在其中获得正确的值


大部分代码都在正确的轨道上,但是您需要从生成器类调用该方法,并将值放入语句的
$setOnInsert
部分,您已经在使用该部分了,但只是还没有包括该
\u id
值。

发生的事情是,只有服务器知道find和modify是否会最终成为一个upsert,而正如目前所写的那样,是服务器自动生成该_id值,并且服务器只能假设该_id值应该是一个ObjectId(服务器对您的类声明一无所知)

下面是一个使用shell的简化示例,展示了您的场景(减去所有C代码…):

我们知道这是一个upsert,因为我们在一个空集合上运行它。请注意,服务器使用该查询作为新文档的初始模板(“x”来自于此),应用了更新规范(“y”来自于此),并且因为该文档没有“\u id”,所以为其生成了一个新的ObjectId

诀窍是在需要时生成_id客户端,但将其放入更新规范中,使其仅适用于新文档。以下是使用$setOnInsert作为_id的前一个示例:

> db.test.drop()
> db.test.find()
> var query = { x : 1 }
> var update = { $setOnInsert : { _id : "E3650127-9B23-4209-9053-1CD989AE62B9", y : 2 } }
> db.test.findAndModify({ query: query, update : update, new : true, upsert : true })
{ "_id" : "E3650127-9B23-4209-9053-1CD989AE62B9", "x" : 1, "y" : 2 }
> db.test.find()
{ "_id" : "E3650127-9B23-4209-9053-1CD989AE62B9", "x" : 1, "y" : 2 }
>
现在我们看到服务器使用了我们提供的_id,而不是生成ObjectId

对于C#代码,只需将以下内容添加到updateQuery中:

updateQuery.SetOnInsert("_id", Guid.NewGuid().ToString());

您应该考虑将UpDATA等式变量重命名为UPDATE特化(或只是更新),因为在技术上它不是查询。


不过有一个问题……这项技术只适用于当前的2.6版本的服务器。请参阅:

因此我确实尝试过这项技术,我应该将其包括在我的ori中
updateQuery.SetOnInsert("_id", Guid.NewGuid().ToString());