首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >EF6事务回滚&并发问题

EF6事务回滚&并发问题
EN

Stack Overflow用户
提问于 2016-02-08 14:26:55
回答 1查看 973关注 0票数 1

一旦我回滚事务并再试一次,它将在DbUpdateConcurrencyException.中失败。

在查看SQL之后,我看到第一次按预期发送INSERT查询,而第二次尝试更新,即使第一个查询已回滚?!

第一个查询:

代码语言:javascript
复制
exec sp_executesql N'INSERT [dbo].[FiscalReceipt]([PurchaseTime], [ReceiptNumber], [Cash], [Card], [Bank])
VALUES (@0, @1, @2, @3, @4)
SELECT [FiscalReceiptID]
FROM [dbo].[FiscalReceipt]
WHERE @@ROWCOUNT > 0 AND [FiscalReceiptID] = scope_identity()',N'@0 datetime2(7),@1 int,@2 decimal(18,2),@3 decimal(18,2),@4 decimal(18,2)',@0='2016-02-08 15:05:43.9145089',@1=666,@2=1.70,@3=0,@4=0

第二个查询:

代码语言:javascript
复制
exec sp_executesql N'UPDATE [dbo].[FiscalReceipt]
SET [PurchaseTime] = @0, [Cash] = @1
WHERE ([FiscalReceiptID] = @2)
',N'@0 datetime2(7),@1 decimal(18,2),@2 int',@0='2016-02-08 15:12:11.8101261',@1=555.00,@2=2042

不应该有TM:Rollback或TM:Commit在SQL表中的EventClass列中吗?

C#代码:

注意: OutOfPaperException打算被忽略,并且该范围内的事务是故意进行的。任何其他异常都应回滚更改。

代码语言:javascript
复制
var transaction = DatabaseContext.Database.BeginTransaction();

            try
            {
                // Commented for debugging
                //IFiscalPrinter fPrinter = DeviceManager.GetFiscalPrinter();
                //var lastReceiptNumber = fPrinter.GetLastReceiptNumber();

                // false data for debugging
                var lastReceiptNumber = 666;
                Receipt.ReceiptNumber = lastReceiptNumber++;
                Receipt.PurchaseTime = DateTime.Now;

                DatabaseContext.SaveChanges();

                //fPrinter.PrintFiscalReceipt(Receipt);

                // Exception for debugging purpose
                if (Receipt.Cash < 500)
                {
                    throw new Exception();
                }

                transaction.Commit();

                Close();
            }
            catch (OutOfPaperException)
            {
                if (transaction != null)
                {
                    transaction.Commit();
                    Close();
                }

                MessageBoxService.ShowMessage("Promenite papir pre sledećeg štampanja!", "Nema više papira!", MessageButton.OK, MessageIcon.Warning);
            }
            catch (Exception ex)
            {
                // I added this but this doesn't help
                Receipt.PurchaseTime = new DateTime();
                Receipt.ReceiptNumber = 0;
                //Receipt.FiscalReceiptID = 0; <- I'm not allowed to do this

                if (transaction != null)
                {
                    transaction.Rollback();
                }

                MessageBoxService.ShowMessage(ex.Message, "Greška!", MessageButton.OK, MessageIcon.Error);
            }
            finally
            {
                if (transaction != null)
                {
                    transaction.Dispose();
                }
            }

DatabaseContext生存期等于视图模型的生存期。

编辑:将适当的条目状态更改为EntryState.Added会导致操作成功,但感觉非常脏。在事务回滚/失败时,条目不应该保持添加状态吗?

运行此代码后的EDIT2:

代码语言:javascript
复制
using (MetalShopDB ctx = new MetalShopDB())
using (var transaction = ctx.Database.BeginTransaction())
{
    var receipt = new FiscalReceipt()
    {
        ReceiptNumber = 555,
        PurchaseTime = DateTime.Now,
        Cash = 100
    };

    ctx.FiscalReceipts.Add(receipt);

    Console.WriteLine("Has changes " + ctx.ChangeTracker.HasChanges());
    Console.WriteLine(ctx.Entry(receipt).State);

    ctx.SaveChanges();

    Console.WriteLine("Saved changes");

    Console.WriteLine("Has changes " + ctx.ChangeTracker.HasChanges());
    Console.WriteLine(ctx.Entry(receipt).State);

    transaction.Rollback();

    Console.WriteLine("Rolled back");

    Console.WriteLine("Has changes " + ctx.ChangeTracker.HasChanges());
    Console.WriteLine(ctx.Entry(receipt).State);
}

我得到了这个输出,我觉得很奇怪,因为人们希望上下文与db同步,所以当您回滚时,上下文应该跟踪这些更改。

代码语言:javascript
复制
Has changes True
Added
Saved changes
Has changes False
Unchanged
Rolled back
Has changes False
Unchanged
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-02-09 14:02:11

为了你的EDIT2

当调用ObjectContext.AcceptAllChanges()方法时,如果在保存时没有发现错误(这是在回滚之后发生的情况),则调用接受更改并填充主键、外键和更改入口状态的SaveChanges方法。

回滚只回滚事务,而不是对象上下文/更改跟踪器。

现在又要调用SaveChanges了,因为实体已经填充了数据库信息,即使回滚也是如此。

原始问题

在SaveChanges成功完成后抛出一个错误(用于调试)

代码语言:javascript
复制
if (Receipt.Cash < 500)
{
    throw new Exception();
}

因此,通过遵循前面的逻辑,AcceptAllChanges已经被调用。

编辑

可以通过使用AcceptAllChanges保存来控制ObjectContext。

代码语言:javascript
复制
var objectContext = ((IObjectContextAdapter) ctx).ObjectContext;
objectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave);

transaction.Commmit();
objectContext.AcceptAllChanges();
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35271989

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档