2

我正在使用时间戳列来检查我的实体中的并发性。当 2 个不同上下文中的数据不相同时,会正确抛出异常。

当保存的时候出现这样的异常,我调用下面的方法来处理:

public static void HandleOptimisticConcurrencyException(ObjectContext context, OptimisticConcurrencyException ex)
{
    string msg = @"The data has changed while you were editing it.
If you save, your changes will override the previous ones.
If you don't, your changes will be lost.

Do you want to save your changes ?";

    var ret = System.Windows.MessageBox.Show(msg, "Concurrency error...", MessageBoxButton.YesNo, MessageBoxImage.Warning);

    if (ret ==  MessageBoxResult.Yes)
    {
        if (ex.StateEntries != null)
        {
            foreach (var item in ex.StateEntries)
            {
                context.Refresh(RefreshMode.ClientWins, item.Entity);
            }
        }
    }
    else
    {
        if (ex.StateEntries != null)
        {
            foreach (var item in ex.StateEntries)
            {
                context.Refresh(RefreshMode.StoreWins, item.Entity);
            }
        }
    }

    context.SaveChanges();
}

我检查了,刷新是在每个故障实体上执行的。但是,第二个SaveChanges()总是重新抛出一个OptimisticConcurrencyException.

难道我做错了什么 ?

提前致谢

编辑

我注意到问题是由于第一次之前的方法调用而出现的SaveChanges()

try
{
    this.UpdateFlags();

    this.repository.Context.SaveChanges();
}
catch (OptimisticConcurrencyException ex)
{
    ExceptionHelpers.HandleOptimisticConcurrencyException(this.repository.Context, ex);
}

如果我注释掉UpdateFlags()电话,我没有问题。

这是此方法的代码:

private void UpdateFlags()
{
    DateTime now = DateTime.Now;

    int masterId = (int)this.navigationContext.Item;

    var master = this.repository.Context.Masters.Where(e => e.Id == masterId).FirstOrDefault();

    foreach (var project in master.Projects)
    {
        // update flags for each project.

        if (project.Dashboard == null)
        {
            project.Dashboard = new Dashboard();
        }

        var flags = project.Dashboard;
        flags.ModifiedOn = now;

        // Update DP flags
        var dpFlag = (int)project.Tasks.Where(e => e.TaskDP != null)
                                   .Select(e => this.CalculateCompletionStatus(e, now))
                                   .DefaultIfEmpty(CompletionStatusType.Ok)
                                   .Max();
        flags.DP = dpFlag;

        // Update TRS flags
        var trsFlag = (int)project.Tasks.Where(e => e.TaskTRSs != null)
                                   .Select(e => this.CalculateCompletionStatus(e, now))
                                   .DefaultIfEmpty(CompletionStatusType.Ok)
                                   .Max();
        flags.TRS = trsFlag;

        // Update REV flags
        var revFlag = (int)project.Tasks.Where(e => e.TaskREV != null)
                                   .Select(e => this.CalculateCompletionStatus(e, now))
                                   .DefaultIfEmpty(CompletionStatusType.Ok)
                                   .Max();
        flags.REV = revFlag;

        // Update DTP flags
        var dtpFlag = (int)project.Tasks.Where(e => e.TaskDTP != null)
                                   .Select(e => this.CalculateCompletionStatus(e, now))
                                   .DefaultIfEmpty(CompletionStatusType.Ok)
                                   .Max();
        flags.DTP = dtpFlag;

        // Update DEL flags
        var delFlag = (int)project.Tasks.Where(e => e.TaskDEL != null)
                                   .Select(e => this.CalculateCompletionStatus(e, now))
                                   .DefaultIfEmpty(CompletionStatusType.Ok)
                                   .Max();
        flags.DEL = delFlag;

        // Update FIN Flag
        var finFlag = (int)project.SalesTasks.Select(e => this.CalculateCompletionStatus(e, now))
                                             .DefaultIfEmpty(CompletionStatusType.Ok)
                                             .Max();
        flags.FIN = finFlag;

        // Update Project flag
        if (flags.REV == (int)CompletionStatusType.Client && project.DTPBeforeReview.HasValue && project.DTPBeforeReview.Value == false)
        {
            // Corner case : Review is late because of an external person (= grey) and DTP Before REV is not set
            // => all moments after REV are not taken in account.
            var projFlag = new List<int> { dpFlag, trsFlag, revFlag }.Max();
            flags.ProjectStatus = projFlag;
        }
        else
        {
            var projFlag = new List<int> { dpFlag, trsFlag, revFlag, dtpFlag, delFlag, finFlag }.Max();
            flags.ProjectStatus = projFlag;
        }
    }
}

但是我看不出问题出在哪里,因为这是在第一次之前完成的SaveChanges()

4

1 回答 1

3

好的,我想我找到了解决方法。

问题不在于导致第一个异常的第一个对象,而在于该对象的更深层次。为了解决这个问题,我像这样更新了我的方法:

public static void HandleOptimisticConcurrencyException(ObjectContext context, OptimisticConcurrencyException ex)
{
    string msg = @"The data has changed while you were editing it.
If you save, your changes will override the previous ones.
If you don't, your changes will be lost.

Do you want to save your changes ?";

    var ret = System.Windows.MessageBox.Show(msg, "Concurrency error...", MessageBoxButton.YesNo, MessageBoxImage.Warning);

    if (ret ==  MessageBoxResult.Yes)
    {
        if (ex.StateEntries != null)
        {
            foreach (var item in ex.StateEntries)
            {
                context.Refresh(RefreshMode.ClientWins, item.Entity);
            }
        }
    }
    else
    {
        if (ex.StateEntries != null)
        {
            foreach (var item in ex.StateEntries)
            {
                context.Refresh(RefreshMode.StoreWins, item.Entity);
            }
        }
    }

    do
    {
        try
        {
            context.SaveChanges();
            break;
        }
        catch (OptimisticConcurrencyException ex2)
        {
            if (ret == MessageBoxResult.Yes)
            {
                foreach (var item in ex2.StateEntries)
                {
                    context.Refresh(RefreshMode.ClientWins, item.Entity);
                }
            }
            else
            {
                foreach (var item in ex2.StateEntries)
                {
                    context.Refresh(RefreshMode.StoreWins, item.Entity);
                }
            }
        }
    }
    while (true);
}

不过,我愿意接受任何其他更好的建议......

于 2012-09-13T12:54:47.213 回答