TransactionScope不会在异常CSLA 4.3上回滚

时间:2013-02-12 20:49:50

标签: transactionscope csla

我有一个带有子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.");
    }
}

Sample project

2 个答案:

答案 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.");
            }
        }
    }