2010-11-30 47 views
2

我在开发的Windows服务中遇到了一些问题,我似乎有使用LINQ的数据库冲突,我想我明白为什么问题正在发生但希望得到一些建议来解决它。问题在使用LINQ的C#窗口服务

我有一个数据库,其中包含一个表格,用于保存需要从服务以特定间隔发送的消息,这里是我的代码片段。

protected override void OnStart(string[] args) 
    { 
     timer = new Timer(10000); 
     timer.Elapsed += new ElapsedEventHandler(TimeElapsed); 
     timer.Interval = 10000; 
     timer.Start(); 
     EventLogger.LogEvent("Timer started succesfuly", EventLogEntryType.Information); 

    } 

    protected override void OnStop() 
    { 
     if (timer != null) 
      timer.Stop(); 
     EventLogger.LogEvent("Timer stopped.", EventLogEntryType.Information); 
    } 

    private void TimeElapsed(object source, ElapsedEventArgs e) 
    { 
     try 
     { 
      EventLogger.LogEvent("Checking for reversals", EventLogEntryType.Information); 
      //We now need to check for reversals that are waiting to be sent 
      ReversalsDataContext db = new ReversalsDataContext(); 
      var reversals = db.FiReversals.Where(r => r.Status == Reversal.ReversalStatus.WAITING_TO_SEND); 

      if (reversals.Any()) 
      { 
       EventLogger.LogEvent(reversals.Count() + " reversals found and being processed.", EventLogEntryType.Information); 
       //Mark the reversal 
       foreach (var rev in reversals) 
       { 
        MarkReversal(rev); 
       } 
       db.SubmitChanges(); 



       //We now need to send the reversal 
       foreach (var rev in reversals) 
       { 
        SendReversal(rev); 
       } 
       db.SubmitChanges(); 
       EventLogger.LogEvent("Finished processing reversal queue", EventLogEntryType.Information); 
      } 
     } 
     catch (Exception ex) 
     { 
      EventLogger.LogEvent(ex.Message + "\n" + ex.StackTrace, EventLogEntryType.Error); 
     } 
    } 

我得到的错误现在是不是发现或改变

行。 在System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode) 在System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) 在System.Data.Linq.DataContext.SubmitChanges() 在EftcObReversalService.EftcObReversalService.TimeElapsed (对象源,ElapsedEventArgs E)

从我所看到的是,这是从下面的代码引起的,

if (reversals.Any()) 
      { 
       EventLogger.LogEvent(reversals.Count() + " reversals found and being processed.", EventLogEntryType.Information); 
       //Mark the reversal 
       foreach (var rev in reversals) 
       { 
        MarkReversal(rev); 
       } 
       db.SubmitChanges(); 



       //We now need to send the reversal 
       foreach (var rev in reversals) 
       { 
        SendReversal(rev); 
       } 
       db.SubmitChanges(); 
       EventLogger.LogEvent("Finished processing reversal queue", EventLogEntryType.Information); 
      } 

这里发生的事情是,我从什么是标有“WAITING_TO_SEND表读取“,一旦我决定将这些条目标记为”PENDING“状态。我这样做是因为我不希望当计时器摆动并且此线程尚未完成时再次读入条目。

一旦我标记了所有条目,我就会在SendReversal方法中处理每个条目,并在完成状态时将状态标记为“COMPLETED”,或将状态更改回“WAITING_TO_SEND”。

我认为这个错误是由2 db.SubmitChanges引起的,因为条目有变化,并且已经被第一次提交并且与第二次提交不同。

如果有人有任何想法或解决方案,请让我知道。

回答

1

好感谢墨菲的意见,我发现我的解决方案,这是如果有人想参考,

在我的服务,我有

private ReversalSender _revSender; 
    private Thread _revSenderThread; 

    public EftcObReversalService() 
    { 
     InitializeComponent(); 
    } 

    protected override void OnStart(string[] args) 
    { 
     _revSender = new ReversalSender(); 
     _revSenderThread = new Thread(new ThreadStart(_revSender.Run)); 
     _revSenderThread.Start(); 

     var timer = new System.Timers.Timer(5000); 
     timer.Elapsed += new ElapsedEventHandler(TimerElapsed); 
     timer.Start(); 
    } 

    void TimerElapsed(object sender, ElapsedEventArgs e) 
    { 
     _revSender.Signal(); 
    } 

    protected override void OnStop() 
    { 
     _revSender.Stop(); 
     _revSenderThread.Join(60000); 
    } 

我们确保我们没有并发问题访问数据库ReversalSender有手动重置事件

public class ReversalSender 
{ 
    private bool _running = true; 
    private ManualResetEvent _reset = new ManualResetEvent(false); 

    public void Run() 
    { 
     while (_running) 
     { 
      _reset.WaitOne(); 
      //We now need to grab all the waiting reversals 
      ReversalsDataContext db = new ReversalsDataContext(); 
      var reversals = db.FiReversals.Where(r => r.Status == Reversal.ReversalStatus.WAITING_TO_SEND); 
      if (reversals.Any()) 
      { 
       foreach (var rev in reversals) 
       { 
        if (_running) 
         SendReversal(rev); 
       } 
      } 
      db.SubmitChanges(); 
     } 
    } 

    private void SendReversal(FiReversal rev) 
    { 
     ..... 
    } 

    public void Signal() 
    { 
     _reset.Set(); 
    } 

    public void Stop() 
    { 
     _running = false; 
    } 
} 
0

只是一个预感,但我认为你是在正确的轨道上。尝试删除对db.SaveChanges()的第一个调用。

if (reversals.Any()) 
{ 
    foreach (var rev in reversals) 
    { 
     MarkReversal(rev); 
    }  

    //We now need to send the reversal 
    foreach (var rev in reversals) 
    { 
     SendReversal(rev); 
    } 

    db.SubmitChanges();     
} 

编辑: 你能不能做到这一点:

if (reversals.Any()) 
{ 
    foreach (var rev in reversals) 
    { 
     MarkReversal(rev); 
     SendReversal(rev); 
    } 

    db.SubmitChanges(); 
} 

不要在每个对象的相同背景下的两个呼叫。

+0

谢谢你的, et,所以如果我已经完成了入口,并且定时器摇摆,我是否有冒险拉入我已经拥有的条目? – 2010-11-30 09:03:10

+0

由于MarkReversal的要点是处理并发性问题,因此失败 - 如果不保存更改,可能会尝试多次处理相同的记录。 – Murph 2010-11-30 09:04:09

2

我刚才建议最简单的解决方案是重新寻找“待定”......但当然如果这个过程将会超出,它实际上并不能解决问题。

有一对夫妇的,我可以快速查看选项:

  1. 变化的逻辑,这样你只能运行在同一时间处理循环的一个实例 - 基本上,如果你已经在处理即可不要开始如此跳过或重新安排时间。
  2. 除了更改状态,您还需要添加一个批号,以便您可以在第一次保存后重新查询,但将该查询限制为针对特定批号的待处理项 - 我已经在过去完成了此操作并拥有它合理地提供错误处理的工作非常聪明,以便能够在事后出现异常时进行整理。