使用mongodb 4.08社区服务器的多文档事务在c#中不起作用

使用mongodb 4.08社区服务器的多文档事务在c#中不起作用,c#,mongodb,transactions,mongodb-.net-driver,C#,Mongodb,Transactions,Mongodb .net Driver,我需要使用mongodb事务更新多个文档,mongodb社区服务器版本是4.08,mongodb驱动程序的.net版本是2.9测试版(也尝试了2.8版)。通过调试,我可以看到它执行了“session.AbortTransaction();”,但数据仍然被插入 var client = new MongoClient(_config.GetConnectionString(ProductMongoDBContext.DATABASE_CONNECTION_STRING)); var session

我需要使用mongodb事务更新多个文档,mongodb社区服务器版本是4.08,mongodb驱动程序的.net版本是2.9测试版(也尝试了2.8版)。通过调试,我可以看到它执行了“session.AbortTransaction();”,但数据仍然被插入

var client = new MongoClient(_config.GetConnectionString(ProductMongoDBContext.DATABASE_CONNECTION_STRING));
var session = client.StartSession();

try
{
    session.StartTransaction();
    //var database = session.Client.GetDatabase(ProductMongoDBContext.DATABASE_NAME);
    var orders = session.Client.GetDatabase(ProductMongoDBContext.DATABASE_NAME).GetCollection<DALOrder>(ProductMongoDBContext.TABLE_NAME_ORDER);
    var products = session.Client.GetDatabase(ProductMongoDBContext.DATABASE_NAME).GetCollection<DALProduct>(ProductMongoDBContext.TABLE_NAME_PRODUCT);

DateTime dtNow = DateTime.Now.ToUniversalTime();
await orders.InsertOneAsync(new DALOrder
{
    ID = order.ID,
    ProductID = Guid.Parse(order.ProductID),
    Size = order.Size,
    Taste = order.Taste,
    TextOnCake = order.TextOnCake,
    Consignee = order.Consignee,
    ConsigneeAddress = order.ConsigneeAddress,
    ConsigneePhone = order.ConsigneePhone,
    DeliveryTime = order.DeliveryTime.ToUniversalTime(),
    DeliveryWay = order.DeliveryWay,
    OrderDepartment = order.OrderDepartment,
    Remarks = order.Remarks,
    State = OrderState.New.ToString(),
    CreatedTime = dtNow,
    UpdatedTime = dtNow
});

// After order created, decrease product inventory by one
var productInfo = products.Find<DALProduct>(p => p.ID.ToString().Equals(order.ProductID)).FirstOrDefault();
productInfo.Inventory -= 1;
await products.ReplaceOneAsync<DALProduct>(p => p.ID.ToString().Equals(order.ProductID), productInfo);

session.CommitTransaction();

return true;
}
catch (Exception e)
{
    session.AbortTransaction();
    order.Message = e.Message;
}
var client=newmongoclient(_config.GetConnectionString(ProductMongoDBContext.DATABASE_CONNECTION_STRING));
var session=client.StartSession();
尝试
{
session.StartTransaction();
//var database=session.Client.GetDatabase(ProductMongoDBContext.database_NAME);
var orders=session.Client.GetDatabase(ProductMongoDBContext.DATABASE_NAME).GetCollection(ProductMongoDBContext.TABLE_NAME_ORDER);
var products=session.Client.GetDatabase(ProductMongoDBContext.DATABASE_NAME).GetCollection(ProductMongoDBContext.TABLE_NAME_PRODUCT);
DateTime dtNow=DateTime.Now.ToUniversalTime();
等待订单。InsertOneAsync(新订单
{
ID=order.ID,
ProductID=Guid.Parse(order.ProductID),
大小=订单。大小,
味道,味道,
TextOnCake=order.TextOnCake,
收货人=订单。收货人,
DelegatedAddress=order.DelegatedAddress,
收货人电话,
DeliveryTime=order.DeliveryTime.ToUniversalTime(),
DeliveryWay=order.DeliveryWay,
OrderDepartment=order.OrderDepartment,
备注=订单。备注,
State=OrderState.New.ToString(),
CreatedTime=dtNow,
updatetime=dtNow
});
//创建订单后,将产品库存减少1
var productInfo=products.Find(p=>p.ID.ToString().Equals(order.ProductID)).FirstOrDefault();
productInfo.Inventory-=1;
wait products.ReplaceOneAsync(p=>p.ID.ToString().Equals(order.ProductID),productInfo);
session.CommitTransaction();
返回true;
}
捕获(例外e)
{
session.AbortTransaction();
order.Message=e.Message;
}
预期插入的订单数据可以回滚,实际结果是数据已插入数据库

顺便说一句,错误发生在

    var productInfo = products.Find<DALProduct>(p => p.ID.ToString().Equals(order.ProductID)).FirstOrDefault();
I define ID as GUID in model like below
    [BsonId]
    public Guid ID { get; set; }
var productInfo=products.Find(p=>p.ID.ToString().Equals(order.ProductID)).FirstOrDefault();
我在模型中将ID定义为GUID,如下所示
[BsonId]
公共Guid ID{get;set;}
它将抛出类似于
“{document}{{u id}的异常。不支持ToString()
如何避免这种情况

我可以看到它执行“session.AbortTransaction();”,但数据仍然被插入

var client = new MongoClient(_config.GetConnectionString(ProductMongoDBContext.DATABASE_CONNECTION_STRING));
var session = client.StartSession();

try
{
    session.StartTransaction();
    //var database = session.Client.GetDatabase(ProductMongoDBContext.DATABASE_NAME);
    var orders = session.Client.GetDatabase(ProductMongoDBContext.DATABASE_NAME).GetCollection<DALOrder>(ProductMongoDBContext.TABLE_NAME_ORDER);
    var products = session.Client.GetDatabase(ProductMongoDBContext.DATABASE_NAME).GetCollection<DALProduct>(ProductMongoDBContext.TABLE_NAME_PRODUCT);

DateTime dtNow = DateTime.Now.ToUniversalTime();
await orders.InsertOneAsync(new DALOrder
{
    ID = order.ID,
    ProductID = Guid.Parse(order.ProductID),
    Size = order.Size,
    Taste = order.Taste,
    TextOnCake = order.TextOnCake,
    Consignee = order.Consignee,
    ConsigneeAddress = order.ConsigneeAddress,
    ConsigneePhone = order.ConsigneePhone,
    DeliveryTime = order.DeliveryTime.ToUniversalTime(),
    DeliveryWay = order.DeliveryWay,
    OrderDepartment = order.OrderDepartment,
    Remarks = order.Remarks,
    State = OrderState.New.ToString(),
    CreatedTime = dtNow,
    UpdatedTime = dtNow
});

// After order created, decrease product inventory by one
var productInfo = products.Find<DALProduct>(p => p.ID.ToString().Equals(order.ProductID)).FirstOrDefault();
productInfo.Inventory -= 1;
await products.ReplaceOneAsync<DALProduct>(p => p.ID.ToString().Equals(order.ProductID), productInfo);

session.CommitTransaction();

return true;
}
catch (Exception e)
{
    session.AbortTransaction();
    order.Message = e.Message;
}
执行操作的原因(即中止后仍插入数据),因为操作不包含在事务会话中

所有CRUD操作都应该有一个重载方法,该方法将
IClientSessionHandle
指定为其第一个参数。例如:

Task InsertOneAsync(IClientSessionHandle session, TDocument document, InsertOneOptions options = null, CancellationToken cancellationToken = default(CancellationToken));
请参阅:和MongoDB.NET/C#driver v2.8.1


要确保操作包含在事务会话中,请将会话作为参数传递给CRUD操作。任何没有会话对象的操作都将在会话之外执行

正如Wan在下面指出的,您需要将会话传递给每个操作系统。如果您不想这样做,JohnKnoop.MongoRepository提供了一个自动登记当前事务的抽象: