EF DbContext 不一致
EF DbContext incosistency
我有以下 class:
public class ATMClient
{
private ATMDbContext dbContext;
private IOutputProvider outputProvider;
public ATMClient(ATMDbContext dbContext)
: this(dbContext, new ConsoleOutputProvider())
{
}
public ATMClient(ATMDbContext dbContext, IOutputProvider outputProvider)
{
this.dbContext = dbContext;
this.outputProvider = outputProvider;
}
public void WithdrawMoney(string cardNumber, string cardPIN, decimal money)
{
using (var transaction = dbContext.Database.BeginTransaction(IsolationLevel.RepeatableRead))
{
var currentAccount = dbContext.CardAccounts.Where(x => x.CardNumber == cardNumber).FirstOrDefault();
try
{
currentAccount.CardCash -= money;
throw new ArgumentException("On purpose exception");
...
dbContext.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
outputProvider.PrintLine(ex.Message);
transaction.Rollback();
dbContext = new ATMDbContext();
}
Console.WriteLine();
Console.WriteLine("On context recreation: ");
Console.WriteLine("----------------------------");
Console.WriteLine(dbContext.CardAccounts.FirstOrDefault(x => x.CardNumber == cardNumber).CardCash);
Console.WriteLine("----------------------------");
Console.WriteLine();
}
}
}
我正在使用以下方法进行测试:
public static void Main()
{
var dbContext = new ATMDbContext();
var atm = new ATMClient(dbContext);
var account = dbContext.CardAccounts.Where(x => x.CardCash >= 10000).FirstOrDefault();
Console.WriteLine();
Console.WriteLine("Before withdraw: ");
Console.WriteLine("-----------------------------------");
Console.WriteLine(account.CardNumber);
Console.WriteLine(account.CardCash);
Console.WriteLine("-----------------------------------");
Console.WriteLine();
atm.WithdrawMoney(account.CardNumber, account.CardPIN, 10000m);
account = dbContext.CardAccounts.Where(x => x.CardNumber == account.CardNumber).FirstOrDefault();
Console.WriteLine();
Console.WriteLine("After withdraw: ");
Console.WriteLine("-----------------------------------");
Console.WriteLine(account.CardNumber);
Console.WriteLine(account.CardCash);
Console.WriteLine("-----------------------------------");
Console.WriteLine();
}
我得到的最终结果:
Before withdraw:
-----------------------------------
0030972041
224027.53
-----------------------------------
On purpose exception
On context recreation:
----------------------------
224027.53
----------------------------
After withdraw:
-----------------------------------
0030972041
214027.53
-----------------------------------
出于某种原因,"after withdraw" 打印使用了不正确的上下文,即使我已经在 Withdraw 方法中重新创建了它。这种行为的原因可能是什么?
我不知道您要实现什么行为,但我怀疑您希望 Main 方法中局部变量的上下文发生变化,因为您将它作为参数传递给了构造函数。这不是引用的工作方式。当您将引用作为参数传递时,会将引用的副本提供给方法。如果它被另一个引用替换,则原始变量不会改变。在 Main 方法中,您仍然使用在第一行初始化的对象。
如果您希望该方法能够更改引用,您应该将参数声明为 "ref",但我怀疑这是您想要实现的任何目标的最佳解决方案。
我有以下 class:
public class ATMClient
{
private ATMDbContext dbContext;
private IOutputProvider outputProvider;
public ATMClient(ATMDbContext dbContext)
: this(dbContext, new ConsoleOutputProvider())
{
}
public ATMClient(ATMDbContext dbContext, IOutputProvider outputProvider)
{
this.dbContext = dbContext;
this.outputProvider = outputProvider;
}
public void WithdrawMoney(string cardNumber, string cardPIN, decimal money)
{
using (var transaction = dbContext.Database.BeginTransaction(IsolationLevel.RepeatableRead))
{
var currentAccount = dbContext.CardAccounts.Where(x => x.CardNumber == cardNumber).FirstOrDefault();
try
{
currentAccount.CardCash -= money;
throw new ArgumentException("On purpose exception");
...
dbContext.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
outputProvider.PrintLine(ex.Message);
transaction.Rollback();
dbContext = new ATMDbContext();
}
Console.WriteLine();
Console.WriteLine("On context recreation: ");
Console.WriteLine("----------------------------");
Console.WriteLine(dbContext.CardAccounts.FirstOrDefault(x => x.CardNumber == cardNumber).CardCash);
Console.WriteLine("----------------------------");
Console.WriteLine();
}
}
}
我正在使用以下方法进行测试:
public static void Main()
{
var dbContext = new ATMDbContext();
var atm = new ATMClient(dbContext);
var account = dbContext.CardAccounts.Where(x => x.CardCash >= 10000).FirstOrDefault();
Console.WriteLine();
Console.WriteLine("Before withdraw: ");
Console.WriteLine("-----------------------------------");
Console.WriteLine(account.CardNumber);
Console.WriteLine(account.CardCash);
Console.WriteLine("-----------------------------------");
Console.WriteLine();
atm.WithdrawMoney(account.CardNumber, account.CardPIN, 10000m);
account = dbContext.CardAccounts.Where(x => x.CardNumber == account.CardNumber).FirstOrDefault();
Console.WriteLine();
Console.WriteLine("After withdraw: ");
Console.WriteLine("-----------------------------------");
Console.WriteLine(account.CardNumber);
Console.WriteLine(account.CardCash);
Console.WriteLine("-----------------------------------");
Console.WriteLine();
}
我得到的最终结果:
Before withdraw:
-----------------------------------
0030972041
224027.53
-----------------------------------
On purpose exception
On context recreation:
----------------------------
224027.53
----------------------------
After withdraw:
-----------------------------------
0030972041
214027.53
-----------------------------------
出于某种原因,"after withdraw" 打印使用了不正确的上下文,即使我已经在 Withdraw 方法中重新创建了它。这种行为的原因可能是什么?
我不知道您要实现什么行为,但我怀疑您希望 Main 方法中局部变量的上下文发生变化,因为您将它作为参数传递给了构造函数。这不是引用的工作方式。当您将引用作为参数传递时,会将引用的副本提供给方法。如果它被另一个引用替换,则原始变量不会改变。在 Main 方法中,您仍然使用在第一行初始化的对象。
如果您希望该方法能够更改引用,您应该将参数声明为 "ref",但我怀疑这是您想要实现的任何目标的最佳解决方案。