2010-11-30 48 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. 除了更改狀態,您還需要添加一個批號,以便您可以在第一次保存後重新查詢,但將該查詢限制爲針對特定批號的待處理項 - 我已經在過去完成了此操作並擁有它合理地提供錯誤處理的工作非常聰明,以便能夠在事後出現異常時進行整理。