0

我有一个 BO(国家)和一个孩子 BO(州),还有一个孩子 BO(城市)。当我更新父 BO(国家),添加子状态并运行保存时,当 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);
        }
    }

国家.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.");
    }
}

示例项目

4

2 回答 2

1

根据我对 SQL CE 和事务的理解,它们在使用 TransactionScope 时仅支持单个数据库连接上的事务。

看起来您的代码遵循某些 CSLA 示例提出的模型,但数据库连接的实际打开/关闭隐藏在 GetManager 或 GetProvider 抽象中,因此无法确定如何处理。

不过,SQL CE 似乎对 TransactionScope 的事务有一些限制,所以你应该确保你没有以某种方式违反他们的限制之一。

于 2013-02-13T05:57:20.580 回答
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.");
            }
        }
    }
于 2013-02-13T13:58:04.560 回答