我有一个带有子BO(州)的BO(国家),它还有一个子BO(城市)。当我更新父BO(国家/地区)时,添加子状态并运行save,当DAL中发生异常时(故意),事务不会回滚。我正在使用SqlCE。我正在附加一个展示问题的样本剥离项目。我做错了什么?
测试代码:
Country originalCountry = null;
try
{
originalCountry = Country.GetCountry(1);
var country = Country.GetCountry(1);
country.CountryName = "My new name";
var state = country.States.AddNew();
state.StateName = "Dummy state";
country.States.EndNew(country.States.IndexOf(state));
country.Save();
}
catch (Exception exception)
{
var country = Country.GetCountry(1);
if (originalCountry.CountryName != country.CountryName)
{
System.Console.WriteLine("Values ARE NOT the same: " + originalCountry.CountryName + " vs. " + country.CountryName);
}
else
{
System.Console.WriteLine("Values are the same: " + originalCountry.CountryName + " vs. " + country.CountryName);
}
}
Country.cs
[Transactional(TransactionalTypes.TransactionScope)]
protected override void DataPortal_Update()
{
Update();
}
private void Update()
{
using (var ctx = DalFactory.GetManager())
{
var dal = ctx.GetProvider<ICountryDal>();
using (BypassPropertyChecks)
{
var dto = new CountryDto();
TransferToDto(dto);
dal.Update(dto);
}
FieldManager.UpdateChildren(this);
throw new Exception("Rollback should occur.");
}
}
答案 0 :(得分:1)
根据我对SQL CE和事务的理解,它们仅在使用TransactionScope时支持单个数据库连接上的事务。
看起来您的代码遵循某些CSLA示例提出的模型,但数据库连接的实际打开/关闭隐藏在GetManager或GetProvider抽象中,所以没有办法确定这是怎么回事处理。
似乎SQL CE对TransactionScope的事务有一些限制,所以你应该确保你没有以某种方式违反他们的一个限制。
答案 1 :(得分:0)
DalManager(和ConnectionManager)依赖于引用计数来确定何时关闭实际连接。
规则并未确保处理DalManager,因此DalManager和引用计数已关闭。导致在其中一个Fetch操作中创建和打开的连接上发生更新,因此不会在Update方法的TransactionScope中登记。
请参阅:http://msdn.microsoft.com/en-us/library/bb896149%28v=sql.100%29.aspx
必须更改所有规则以处置DalManager。原规则:
protected override void Execute(RuleContext context)
{
var name = (string)context.InputPropertyValues[_nameProperty];
var id = (int)context.InputPropertyValues[_idProperty];
var dal = DalFactory.GetManager();
var countryDal = dal.GetProvider<ICountryDal>();
var exists = countryDal.Exists(id, name);
if (exists)
{
context.AddErrorResult("Country with the same name already exists in the database.");
}
}
DalManager是IDisposable但未在此明确处理,因此它取决于GC实际收集对象的时间。
应该是:
protected override void Execute(RuleContext context)
{
var name = (string)context.InputPropertyValues[_nameProperty];
var id = (int)context.InputPropertyValues[_idProperty];
using (var dal = DalFactory.GetManager())
{
var countryDal = dal.GetProvider<ICountryDal>();
var exists = countryDal.Exists(id, name);
if (exists)
{
context.AddErrorResult("Country with the same name already exists in the database.");
}
}
}