实体框架OptimisticConcurrencyException在刷新后重新抛出 [英] Entity framework OptimisticConcurrencyException rethrown after refresh

查看:191
本文介绍了实体框架OptimisticConcurrencyException在刷新后重新抛出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



当保存时发生这种异常时,我调用以下方法来处理它: p>

  public static void HandleOptimisticConcurrencyException(ObjectContext context,OptimisticConcurrencyException ex)
{
string msg = @
如果您保存,您的更改将覆盖以前的更改
如果没有,您的更改将丢失

你想要保存您的更改?;

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项目在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() code> call,我没有问题。



这是这个方法的代码:

  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)
{
//为每个项目更新标志。

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

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

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

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

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

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

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

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

//更新项目标志
if(flags.REV ==(int)CompletionStatusType.Client&& project.DTPBeforeReview.HasValue&&&project.DTPBeforeReview.Value == false)
{
//角落案例:由于外部人员(=灰色)和DTP审查迟到REV未设置
// => REV之后的所有时刻都不被考虑。
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()

解决方案

确定我想我已经找到了解决方法。



问题不是来自第一个引起第一个异常的对象,但更深入这个对象。
要解决这个问题,我更新了我的方法如下:

  public static void HandleOptimisticConcurrencyException(ObjectContext context,OptimisticConcurrencyException ex) 
{
string msg = @在编辑时数据已更改
如果保存,您的更改将覆盖以前的更改
如果没有,您的更改将会丢失

您要保存更改吗?

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项目在ex.StateEntries中)
{
context.Refresh(RefreshMode.StoreWins,item.Entity);
}
}
}

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

我可以接受任何其他更好的建议...


I'm using a timestamp column to check the concurrency in my entity. The exception is correctly thrown when data is not the same in 2 different contexts.

When such an exception occurs when saving, I call the following method to handle it:

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

I checked, and the refresh is executed on each faulted entity. However, the second SaveChanges() always rethrows an OptimisticConcurrencyException.

Am I doing something wrong ?

Thanks in advance

Edit

I've noticed that the problem arises because of a method call before the first SaveChanges()

try
{
    this.UpdateFlags();

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

If I comment out the UpdateFlags() call, I have no problem.

Here is the code for this method:

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;
        }
    }
}

However I don't see where the problem is, as this is made before the first SaveChanges()

解决方案

Ok I think I found how to solve that.

The problem doesn't come from the first object who causes the first exception, but deeper in this object. To solve that, I updated my method like this:

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);
}

I'm open to any other better suggestion though...

这篇关于实体框架OptimisticConcurrencyException在刷新后重新抛出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆