Транзакция с несколькими документами не работает в C# с использованием сервера сообщества mongodb 4.08

Мне нужно обновить несколько документов, используя транзакцию 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 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; }

будет выбрасывать исключение как "{document}{_id}.ToString() is not supported."Как этого избежать

1 ответ

Я вижу, что он выполнил 'session.AbortTransaction();', но данные все еще были вставлены.

Причина, по которой операции выполняются (т. Е. Данные все еще были вставлены после прерывания), потому что операции не содержатся в транзакционном сеансе.

Все операции CRUD должны иметь перегруженные методы, определяющие IClientSessionHandleв качестве первого аргумента. Например:

Task InsertOneAsync(IClientSessionHandle session, TDocument document, InsertOneOptions options = null, CancellationToken cancellationToken = default(CancellationToken));

См. InsertOneAsync и ReplaceOneAsync в драйвере MongoDB .NET/C# v2.8.1.

Чтобы гарантировать, что операции содержатся в транзакционном сеансе, передайте сеанс в качестве аргумента операциям CRUD. Любые операции, не имеющие объекта сеанса, будут выполняться вне сеанса.

В Visual Studio вы можете навести курсор на Find<DALProduct> метод, и вы увидите, что он ожидает параметр типа Expression<Func<DALProduct, bool>>, Это означает, что это выражение будет переведено на язык запросов MongoDB.

К сожалению невозможно перевести ToString() в запрос MongoDB с помощью драйвера C#. Хорошей новостью является то, что вам не нужно этого делать - вы можете сравнивать значения guid напрямую (сохраняются как BinData в MongoDB), используя следующий код:

var guid = Guid.Parse(order.ProductID);
var productInfo = products.Find<DALProduct>(p => p.ID == guid).FirstOrDefault();

РЕДАКТИРОВАТЬ: чтобы исправить вашу транзакцию, вам нужно пройти session к каждой операции CRUD (InsertOneAsync перегружен и одна из его версий занимает IClientSessionHandle как первый параметр)

await orders.InsertOneAsync(session, 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
});
Другие вопросы по тегам