2010-07-13 1 views
3

나는이 다음과 같은 호출 (이것보다 실제로는 몇 가지 더 - 그것은 여기에 질문의 전체 방법입니다) :Monotouch data sync - 내 코드가 때때로 sqlite 오류를 일으키는 이유는 무엇입니까?

ThreadPool.QueueUserWorkItem(Database.Instance.RefreshEventData); 
ThreadPool.QueueUserWorkItem(Database.Instance.RefreshLocationData); 
ThreadPool.QueueUserWorkItem(Database.Instance.RefreshActData); 

1 점 - 그것은이 같은 WCF 서비스를 호출 메소드를 호출 OK인가? 나는 데이지 체이닝을 시도했는데 엉망이었다.

위 호출되는 새로 고침 방법 중 하나의 예는 (그들은 모두 그냥 다른 테이블을 다른 서비스를 호출하고 채우는, 같은 패턴을 따른다)입니다 :

public void RefreshEventData (object state) 
     { 
      Console.WriteLine ("in RefreshEventData"); 
      var eservices = new AppServicesClient (new BasicHttpBinding(), new EndpointAddress (this.ServciceUrl)); 

      //default the delta to an old date so that if this is first run we get everything 
      var eventsLastUpdated = DateTime.Now.AddDays (-100); 

      try { 
       eventsLastUpdated = (from s in GuideStar.Data.Database.Main.Table<GuideStar.Data.Event>() 
        orderby s.DateUpdated descending 
        select s).ToList().FirstOrDefault().DateUpdated; 

      } catch (Exception ex1) { 
       Console.WriteLine (ex1.Message); 
      } 

      try { 
       eservices.GetAuthorisedEventsWithExtendedDataAsync (this.User.Id, this.User.Password, eventsLastUpdated); 
      } catch (Exception ex) { 
       Console.WriteLine ("error updating events: " + ex.Message); 
      } 

      eservices.GetAuthorisedEventsWithExtendedDataCompleted += delegate(object sender, GetAuthorisedEventsWithExtendedDataCompletedEventArgs e) { 

       try { 

        List<Event> newEvents = e.Result.ToList(); 

        GuideStar.Data.Database.Main.EventsAdded = e.Result.Count(); 

        lock (GuideStar.Data.Database.Main) { 
         GuideStar.Data.Database.Main.Execute ("BEGIN"); 

         foreach (var s in newEvents) { 

          GuideStar.Data.Database.Main.InsertOrUpdateEvent (new GuideStar.Data.Event { 
           Name = s.Name, 
           DateAdded = s.DateAdded, 
           DateUpdated = s.DateUpdated, 
           Deleted = s.Deleted, 
           StartDate = s.StartDate, 
           Id = s.Id, 
           Lat = s.Lat, 
           Long = s.Long 
          }); 

         } 

         GuideStar.Data.Database.Main.Execute ("COMMIT"); 
         LocationsCount = 0; 
        } 
       } catch (Exception ex) { 
        Console.WriteLine("error InsertOrUpdateEvent " + ex.Message); 
       } finally { 
        OnDatabaseUpdateStepCompleted (EventArgs.Empty); 
       } 

      }; 
     } 

이 OnDatabaseUpdateStepCompleted -이 때 그냥 updateComplete 카운터를 반복 할 불렀고 모든 서비스가 다시 돌아 왔음을 알았을 때 대기중인 스피너가 제거되고 앱이 계속 실행됩니다.

이 확인 1 시간 '라운드 작동 -하지만 때로는 이들 중 하나하지 않습니다 :

http://monobin.com/__m6c83107d 내가 첫번째 질문은 생각 -이 모든 OK인가? 나는 쓰레딩과 자물쇠를 사용하는 데 익숙하지 않아서 나를 위해 새로운 길로 방황하고있다. 이 같은 QueueUserWorkItem 사용하고 계십니까? 벌크 삽입/업데이트를 수행하기 전에 잠금을 사용해야합니까? 예를 들면 다음과 같습니다.

public void InsertOrUpdateEvent(Event festival){ 

      try { 
       if (!festival.Deleted) { 
        Main.Insert(festival, "OR REPLACE"); 
       }else{ 
        Main.Delete<Event>(festival); 
       } 
      } catch (Exception ex) { 
       Console.WriteLine("InsertOrUpdateEvent failed: " + ex.Message); 
      } 

     } 

다음 질문은 -이 sqlite 문제의 원인은 무엇입니까?

와트 : //

+0

여기 믹스에 몇 가지 아이디어를 던져 - 난 그냥 새로운 데이터를 가져 오는 '복원'사용 후, 서버에 SQLite는 DB를 생성하여 다운로드에 대해 생각하고 있어요. 확실히 서투른. 아마 아주 무거웠지만 최소한 그것은 매번 일할 것이다! 기록을 위해,이 갱신은 항상 편도이다. 서버 -> 아이폰 – iwayneo

+0

그게 효과가있을 수 있습니다. SQL Server -> SQL CE (이전 하나) 복제 시나리오에서도 동일한 작업을 수행했습니다. 마스터 -> 400 슬레이브 (SQL Server에서)로 끝난 다음 SQL Server (400DB 중 하나)에서 SQL ce (장치)로 1 : 1 마스터 -> 슬레이브로 끝납니다. 괜찮 았지만 실제로는 좋은 해결책이 아니 었습니다.위쪽면에서 압축하고 일반적으로 DB를 압축 할 수 있으며 전화 논리를 훨씬 복잡하게 만들 수 있습니다 .... –

+0

cvista, Syncing 목표를 달성 했습니까? 당신은 당신의 지식의 일부 또는 전부를 기꺼이 공유 할 의향이 있습니까? 휠체어를 다시 만들 필요가 없다면 비슷한 문제를 겪고 있습니다. 감사합니다. 릭 – Rick

답변

0

죄송합니다, 구체적인 답변,하지만 몇 가지 생각 :

가 SqlLite에게조차 스레드를인가? 확실하지 않습니다. 포장지가 아니라고 생각할 수도 있습니다. 더 많은 전역 개체를 잠글 수 있으므로 두 스레드가 동시에 삽입되지 않습니까?

MT GC가 약간 과한 반응을 보이고 사용하기 전에 문자열을 공개 할 가능성이 있습니다. 어쩌면 삽입하는 동안 주위에 로컬 참조를 유지? 나는 배열 컨트롤러 (tabcontroller, specificially)를 가지고있는 뷰 컨트롤러에서 이런 일이 발생했다.하지만 멤버 변수를 참조로 유지하지 않으면 GC'ed가 발생한다.

데이터를 스레드 방식으로 가져온 다음 모든 것을 큐에 넣고 단일 스레드에 삽입 할 수 있습니까? 어쨌든 시험으로 치러야합니다.

+0

그래서 싱글 톤 클래스의 락 객체를 가지고 있다면 괜찮을 것입니다. 왜 오 왜 sqlite threadsafe isnt? GuideStar.Data.Database.Main은 또 다른 싱글 톤 클래스입니다. tweetsharp에서 사용 된 패턴 미겔을 따랐습니다. 동시에 db에 대해 아무 것도 실행하지 못하게하는 잠금? – iwayneo

+0

"데이터를 스레드 방식으로 가져올 수 있습니까?"즉 로컬 컬렉션에 캐시 한 다음 다른 컬렉션 이후에 하나의 컬렉션에 내용을 삽입 하시겠습니까? 전에도 이런 일을했지만 그와 비슷한 효과가있었습니다. – iwayneo

+0

sqllite는 스레드 세이프 일 수 있습니다. 래퍼가되지 않을 수도 있습니다. 솔직히 말해서 나는 모른다. 하지만 네 - 데이터베이스 개체에 어떤 종류의 잠금이 도움이 될 수 있습니다. 또는 하나의 스레드에서 하나의 메서드를 만들고 세 메서드를 순차적으로 호출하면 어떤 일이 발생하는지 봅니다. –

3

Sqlite는 스레드로부터 안전하지 않습니다.

하나 이상의 스레드에서 Sqlite에 액세스하려면 SQLite 관련 구조에 액세스하기 전에 잠금을 해제해야합니다. 이처럼

:

lock (db){ 
     // Do your query or insert here 
} 
+0

읽기와 쓰기 모두 수행해야한다. ? 나는 실제로 견실 한 그것을 얻을 수 있었다. 그러나 참조를 위해 - 그리고 어떤 미래의 문제도 부정하기 위해 - 나는 지금 쓰고있을 때만 이것을 쓰고있다. – iwayneo

+0

언제든지 * Sqlite에 접근해야한다. * 아무 것도 * 읽기, 쓰기 또는 검색. –

관련 문제