Search code examples
wpfentity-frameworkbackgroundworker

ObjectContext.SaveChanges with BackgroundWorker


I have problem with ObjectContext.SaveChanges method:

  public void Save(Action<object, object> action)
    {
        EventAggregator.GetEvent<EntityServiceRequestingEvent>().Publish(true);
        var bw = new BackgroundWorker();
        var saved = false;
        bw.DoWork += (o, ee) =>
                         {
                             ProgramStatusService.Status = Resources.DatabaseSavingMessage;


                             if (!CanSave())
                             {
                                 throw new InvalidOperationException(
                                     "You must not call Save when CanSave returns false.");
                             }
                             try
                             {
                                 lock (Context)
                                 {
                                     Context.SaveChanges();
                                     saved = true;    
                                 }
                             }
                             catch (ValidationException e)
                             {
                                 MessageService.ShowError(null, string.Format(CultureInfo.CurrentCulture,
                                                                              Resources.SaveErrorInvalidEntities,
                                                                              e.Message));
                             }
                             catch (UpdateException e)
                             {
                                 var innerException = e.InnerException as SqlException;
                                 if (innerException != null && innerException.Number == 2601)
                                 {
                                     MessageService.ShowError(null, string.Format(CultureInfo.CurrentCulture,
                                                                                  Resources.DublicateKeyUpdateError,
                                                                                  e.InnerException.Message));
                                 }
                                 else
                                 {
                                     MessageService.ShowError(null, string.Format(CultureInfo.CurrentCulture,
                                                                                  Resources.SaveErrorInvalidFields,
                                                                                  e.InnerException.Message));
                                 }
                             }
                             ee.Result = saved;
                         };
        bw.RunWorkerCompleted += (o, e) =>
                                     {
                                         EventAggregator.GetEvent<EntityServiceRequestingEvent>().Publish(false);
                                         ProgramStatusService.Status = Resources.ProgramReadyMessage;
                                         if (e.Result != null) action.Invoke(this, e.Result);
                                     };
        bw.RunWorkerAsync();
    }

While saving i'm getting error: The calling thread cannot access this object because a different thread owns it. in Designer.cs:

   /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    [EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
    [DataMemberAttribute()]
    public Nullable<global::System.DateTime> MDate
    {
        get
        {
            return _MDate;
        }
        set
        {
            OnMDateChanging(value);
            ReportPropertyChanging("MDate");
            _MDate = StructuralObject.SetValidValue(value);
     ReportPropertyChanged("MDate");// **ERROR HERE**

            OnMDateChanged();
        }
    }

How to properly use ObjectContext with BackgroundWorker?


Solution

  • The only correct way to use context in background worker is to create it in DoWork handler, use it and dispose it before DoWork handler ends. ObjectContext is not thread safe and locking it for SaveChanges will not change it.

    The exception you are receiving is not caused by EF but by WPF and UI controls. You cannot modify control from non-UI thread. You must use Dispatcher to work with controls.