EF CORE 6使用事务。entity framework 电脑版发表于:2023/2/24 9:41 如果出现错误:`The connection is already in a transaction and cannot participate in another transaction.`可以进行一下判断 ``` var transaction = Database.CurrentTransaction ?? Database.BeginTransaction() ``` Try to use this helper function for creating a new transaction: ``` public CommittableTransaction CreateTransaction() => new System.Transactions.CommittableTransaction(new TransactionOptions() { IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted }); ``` Using the Northwind database as example database, you can use it like: ``` public async Task<int?> CreateCategoryAsync(Categories category) { if (category?.CategoryName == null) return null; using(var trans = CreateTransaction()) { await this.Context.Categories.AddAsync(category); await this.Context.SaveChangesAsync(); trans.Commit(); return category?.CategoryID; } } ``` And then you can call it from another function like: ``` /// <summary>Create or use existing category with associated products</summary> /// <returns>Returns null if transaction was rolled back, else CategoryID</returns> public async Task<int?> CreateProjectWithStepsAsync(Categories category) { using var trans = CreateTransaction(); int? catId = GetCategoryId(category.CategoryName) ?? await CreateCategoryAsync(category); if (!catId.HasValue || string.IsNullOrWhiteSpace(category.CategoryName)) { trans.Rollback(); return null; } var product1 = new Products() { ProductName = "Product A1", CategoryID = catId }; await this.Context.Products.AddAsync(product1); var product2 = new Products() { ProductName = "Product A2", CategoryID = catId }; await this.Context.Products.AddAsync(product2); await this.Context.SaveChangesAsync(); trans.Commit(); return catId; } ``` To run this with LinqPad you need an entry point (and of course, add the NUGET package EntityFramework 6.x via F4, then create an EntityFramework Core connection): ``` // Main method required for LinqPad UserQuery Context; async Task Main() { Context = this; var category = new Categories() { CategoryName = "Category A1" // CategoryName = "" }; var catId = await CreateProjectWithStepsAsync(category); Console.WriteLine((catId == null) ? "Transaction was aborted." : "Transaction successful."); } ``` This is just a simple example - it does not check if there are any product(s) with the same name existing, it will just create a new one. You can implement that easily, I have shown it in the function CreateProjectWithStepsAsync for the categories: ``` int? catId = GetCategoryId(category.CategoryName) ?? await CreateCategoryAsync(category); ``` First it queries the categories by name (via GetCategoryId(...)), and if the result is null it will create a new category (via CreateCategoryAsync(...)). Also, you need to consider the isolation level: Check out System.Transactions.IsolationLevel to see if the one used here (ReadCommitted) is the right one for you (it is the default setting). What it does is creating a transaction explicitly, and notice that here we have a transaction within a transaction. 原文:https://stackoverflow.com/questions/70958670/how-to-nest-transactions-in-ef-core-6