要求
MongoDB >= 4.0 C# Driver >= 2.7 我是怎么做到的...
TL;博士
转到“示例代码”
会话
在我可以访问我的客户端 (IMongoClient) 的 DbContext 类中,我定义了会话:
public IClientSessionHandle StartSession()
{
return _client.StartSession(new ClientSessionOptions());
}
public async Task<IClientSessionHandle> StartSessionAsync()
{
return await _client.StartSessionAsync(new ClientSessionOptions());
}
正如文档所说,他们能够一个接一个地执行多个事务,只要这些事务一个接一个地进行
会话用于将一系列相互关联的操作组合在一起,并且应该使用相同的会话选项来执行。会话也用于事务。
这些会话说,一旦你结束你的操作,它们应该被关闭......
所以你实际上应该像下面这样编写它,或者根据你的场景执行手动处理:
// db is what i named my context, where i defined all my collections and database related stuffs.
// if you have direct access to client, you can call `StartSession/Async` exactly over the `client` object
using(var session = _db.StartSessionAsync()) {
//... All transactional code will go here
}
// Here, on ending the block, Will automatically call `Dispose` method, and the object will no longer exists
超过session
对象
交易
使用 IClientSession 的方法启动、提交或中止事务。一个会话一次只能执行一个事务,但一个会话可以执行多个事务,只要每个事务在下一个事务开始之前提交或中止即可。
在此步骤中,您需要在实际对数据库执行更改之前启动事务...
session.StartTransaction();
会话开始后,您应该执行交易,最后...
如果过程成功,您应该调用:
session.CommitTransaction();
否则需要回滚
session.AbortTransaction();
示例代码
如您所见,我在 mongodb 上有两个写操作,以及另一个对我而言至关重要的外部进程,我需要将这三个一起执行,.. 前两个由事务管理,只要第三个不'不要抛出异常,数据库应该保持它的新状态。
bool error;
using (var session = await _db.StartSessionAsync())
{
session.StartTransaction();
try
{
var deletedImage = _db.GetUserStore<ApplicationUser>().CollectionInstance.UpdateOneAsync(
Builders<ApplicationUser>.Filter.Where(w => w.Id == userId),
Builders<ApplicationUser>.Update.Pull(x => x.ProfilePictures, photoFromRepo));
await _db.ProfilePicture().DeleteAsync(new ObjectId(photoFromRepo.ImageId));
if (photoFromRepo.CloudinaryPublicId != null)
{
var deleteParams = new DeletionParams(photoFromRepo.CloudinaryPublicId);
var result = _cloudinary.Destroy(deleteParams);
if (result.Result == "ok")
{
// ignore
}
else
{
throw new Exception("Cannot delete file from cloud service...");
}
}
await session.CommitTransactionAsync();
error = false;
}
catch (Exception ex)
{
await session.AbortTransactionAsync();
error = true;
}
}
这行得通吗?它是否支持多个集合?只有上帝知道,我是根据今天早些时候在回家路上看到的文档和一些样本写的,以及我认为这可能是正确和可能的......
额外说明:
您可以通过会话选项,其中一个选项控制读/写问题,另一个控制在执行事务之前应该提前多少数据(这是什么意思?我自己没有得到它,如果你明白的话,请编辑我的帖子)
public class ClientSessionOptions
{
public bool? CausalConsistency { get; set; }
public TransactionOptions DefaultTransactionOptions { get; set; }
}
public class TransactionOptions
{
public ReadConcern ReadConcern { get; };
public ReadPreference ReadPreference { get; };
public WriteConcern WriteConcern { get; };
public TransactionOptions(
Optional<ReadConcern> readConcern = default(Optional<ReadConcern>),
Optional<ReadPreference> readPreference = default(Optional<ReadPreference>),
Optional<WriteConcern> writeConcern = default(Optional<WriteConcern>));
public TransactionOptions With(
Optional<ReadConcern> readConcern = default(Optional<ReadConcern>),
Optional<ReadPreference> readPreference = default(Optional<ReadPreference>),
Optional<WriteConcern> writeConcern = default(Optional<WriteConcern>))
}