刷新后重新生成实体框架OptimisticConcurrencyException

时间:2012-09-13 09:01:38

标签: c# entity-framework-4 optimistic-concurrency

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

保存时发生此类异常时,我调用以下方法来处理它:

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()

1 个答案:

答案 0 :(得分: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);
}

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