locked
Tracking down: System.NotSupportedException was unhandled RRS feed

  • Question

  •  

    I'm having an issue commiting changes in a linq data context. I'm editing a hirarchy of data, but I have direct access to the datacontext the whole time, so I don't have to worry about detaching or attaching objects, simply commiting changes (which simplifies my life ever so greatly).

     

    Here's the issue. I start a new dc, retreive a few objects using the dc, some of which are join entries, edit them, then commit the changes. The first time through it works beautifully, flawlessly. While running the same application I attempt to duplicate the exact same transaction, and I get the dreaded

    "System.NotSupportedException was unhandled
      Message="An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext"

     

    I'm confused! There's only one datacontext, or should be! Anyone have an idea about this?

    Wednesday, February 13, 2008 5:16 PM

Answers

  • I have found and worked around the issue. I honestly don't understand what the problem was, however I managed to make it work.

     

    I had a property I was calling LayoutSource. The elements in LayoutSource were added into an ObservableCollection and the observable collection was used in databinding. There was no good reason for this left (there were several previously but I refactored the control, however this little piece was missed). The selected element in a combo box is tied to an element to save. For some reason, the second time this was saved it died and gave me that error. Checking the properties on the updated element showed everything to be in order, so I don't quite understand what's going on there. All the elements were still from the correct data contexts.

     

    I removed this extra little layer in databinding and it appears to be working fine. It even meant I could take out the Thread.Sleep.

     

    I essentially removed this little step when the LayoutSource property changed

            private void UpdateLayouts()
            {
                Layouts.Clear();
                Layouts.AddRange(LayoutsSource);
            }

     

    And changed the databinding on the combo box to be LayoutsSource instead of Layouts.

     

    That doesn't really make sense, to me either should really work, unless there's something odd about the way observablecollection works (my class inherited from ObservableCollection<Layouts> and added the single method AddRange, which pretty much looks like List<>.AddRange()).

     

    If anyone has an answer as to why this might be, or I can help figure out what might be causing this, let me know!

     

    Cheers,

    Stephen

     

    Sunday, February 17, 2008 8:08 PM

All replies

  • can you paste some code?

     

    Wednesday, February 13, 2008 7:20 PM
  • I was trying to avoid posting too much code, as it's quite a complicated. I'll skip the UI code, since it is all abstracted away from the data anyway:

     

    You'll notice that there's a thread.sleep in there. For whatever reason if that's not in there, the view does not properly display itself. I have a feeling it's because a thread needs to catch up somewhere in the datacontext or in the window.

           

    Code Snippet

    private void EditPlaylist(Playlist playlist, IDataAccessor dataAccessor)
    {
           PlaylistDialog dialog = new PlaylistDialog();
           dialog.BeginInit();
           dialog.Playlist = dataAccessor.RetreivePlaylistForUpdate(playlist.PlaylistGuid);
           Thread.Sleep(100); //this is here because for whatever reason it own't get updated properly if it's not
           dialog.Assets = dataAccessor.GetAssets();
           dialog.AssetTypes = dataAccessor.GetAssetTypes();
           dialog.LayoutsSource = dataAccessor.GetLayouts();
           dialog.EndInit();
                //dialog.Tag = dataAccessor;

           Window w = new Window();
           w.Title = "Edit Playlist";
           w.Content = dialog;
           w.Height = 800;
           w.Width = 1200;

           w.ShowDialog();

           if (dialog.IsDirty)
           {
               MessageBoxResult result = MessageBox.Show(w, "Save changes to playlist?", "Playlist Changed", MessageBoxButton.YesNo);
               if (result == MessageBoxResult.Yes)
               {
                   dialog.SynchronizePlaylist();
                   dataAccessor.UpdatePlaylist(dialog.Playlist);
               }
          }

    }

     

     

     

    The implemented IDataAccessor contains a DataContext created at creation, and implements IDisposable.

    EditPlaylist is called from within a using statement on the button click.

     

    The pertinant methods from the IDataAccessor are as follows

     

    Code Snippet

    public Playlist RetreivePlaylistForUpdate(Guid playlistGuid)
    {

       return _dataContext.Playlists.Where(playlist => playlist.PlaylistGuid == playlistGuid).FirstOrDefault();
    }

     

    public void UpdatePlaylist(Playlist playlist)
    {
         playlist.LastModified = DateTime.Now;           
        _dataContext.SubmitChanges();
    }

     

    //example getter

    public IEnumerable GetAssets()
    {
         return _dataContext.Assets;
    }

     

     

    Wednesday, February 13, 2008 8:06 PM
  • First off, something is obviously wrong if you have to call Sleep(100) to get the update to go through the first time. 

     

    You also mentioned that you are editing based on a join condition.  Is it possible that the second time through you are using a new data context instance and the control that is bound to the join data is referring to the instances that originated from the original DataContext?

     

    What does SynchronizePlaylist() do?  If you are data binding to the actual entity instances why does there need to be a sync step?

     

     

     

    Wednesday, February 13, 2008 8:44 PM
  • Thanks for looking this over.

     

    Alright, let me see...

     

    The sleep call is only necessary the second time through (another issue that I just don't understand). I generate a new control every time here, so I'm not sure why there would be any references hanging around. There are no static properties on the control, unless that's a dependency property issue.

     

    SynchronizePlaylist is necessary because of data visualization issues with data binding, because the data has to go through a MultiValueConverter to be seen in the way I want in the editor.

        

    Code Snippet

        public void SynchronizePlaylist()
            {
                Playlist.PlaylistZoneAssets.Clear();

                PlaylistTimelineValueConverter converter = new PlaylistTimelineValueConverter();
                converter.Playlist = Playlist;
                object[] converted = converter.ConvertBack(this.Timelines.TimelineDataset, null, null, System.Globalization.CultureInfo.InvariantCulture);
                IEnumerable playlistZoneAssets = converted[0] as IEnumerable;
                Playlist.PlaylistZoneAssets.AddRange(playlistZoneAssets);
            }

     

     

     

    I would love to be able to do this without the clear() but I can't see an easy way of dealing with that through a value converter.

     

    The convert back method is as follows

     

         

    Code Snippet

       public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
            {
                TimelineDatasetCollection trackCollection = value as TimelineDatasetCollection;
                ObservableCollection assets = new ObservableCollection();
                ObservableCollection zones = new ObservableCollection();

                if (trackCollection != null)
                {
                    foreach (ZoneAssetTrack track in trackCollection)
                    {
                        zones.Add(track.LayoutZone);
                        int i = 0;
                        foreach (ITimelineSegment segment in track)
                        {
                           
                            AssetTimelineSegment ats = segment as AssetTimelineSegment;
                            if (ats != null)
                            {
                                if (ats.PlaylistZoneAsset.PlaylistZoneAssetGuid == Guid.Empty)
                                    ats.PlaylistZoneAsset.PlaylistZoneAssetGuid = Guid.NewGuid();
                                if (ats.PlaylistZoneAsset.Playlist == null)
                                    ats.PlaylistZoneAsset.Playlist = Playlist;
                                if (ats.PlaylistZoneAsset.Zone == null)
                                    ats.PlaylistZoneAsset.Zone = track.LayoutZone.Zone;

                                ats.PlaylistZoneAsset.Slot = i;
                                ats.PlaylistZoneAsset.LastModified = DateTime.Now;
                                ats.PlaylistZoneAsset.Name = BuildPlaylistZoneAssetName(ats.PlaylistZoneAsset);
                                assets.Add(ats.PlaylistZoneAsset);
                            }
                        }
                    }
                }

     

     

     

               

    Wednesday, February 13, 2008 9:06 PM
  • Could you supply the call tree from the exception?

     

    Thursday, February 14, 2008 12:55 AM
  •  

    Here's the entire exception as it copies out. I hope you can find something more useful in it than I. Thanks for keeping on this, I really appreciate it:

     

    System.NotSupportedException was unhandled
      Message="An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext.  This is not supported."
      Source="System.Data.Linq"
      StackTrace:
           at System.Data.Linq.ChangeTracker.StandardChangeTracker.Track(MetaType mt, Object obj, Dictionary`2 visited, Boolean recurse, Int32 level)
           at System.Data.Linq.ChangeTracker.StandardChangeTracker.Track(Object obj, Boolean recurse)
           at System.Data.Linq.ChangeTracker.StandardChangeTracker.Track(Object obj)
           at System.Data.Linq.ChangeProcessor.TrackUntrackedObjects(MetaType type, Object item, Dictionary`2 visited)
           at System.Data.Linq.ChangeProcessor.TrackUntrackedObjects(MetaType type, Object item, Dictionary`2 visited)
           at System.Data.Linq.ChangeProcessor.TrackUntrackedObjects()
           at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
           at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
           at System.Data.Linq.DataContext.SubmitChanges()
           at Airtime.Admin.AdminConsole.DbDataAccessor.UpdatePlaylist(Playlist playlist) in C:\Users\stephen.verstraete\SourceControl\Airtime\Admin\AdminConsole2\DbDataAccessor.cs:line 87
           at Airtime.Admin.AdminConsole.Controller`1.EditPlaylist(Playlist playlist, IDataAccessor dataAccessor) in C:\Users\stephen.verstraete\SourceControl\Airtime\Admin\AdminConsole2\Controller.cs:line 170
           at Airtime.Admin.AdminConsole.Controller`1.EditPlaylist() in C:\Users\stephen.verstraete\SourceControl\Airtime\Admin\AdminConsole2\Controller.cs:line 139
           at Airtime.Admin.AdminConsole.Window1.playlistEdit_Click(Object sender, RoutedEventArgs e) in C:\Users\stephen.verstraete\SourceControl\Airtime\Admin\AdminConsole2\Window1.xaml.cs:line 43
           at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
           at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
           at System.Windows.UIElement.RaiseEventImpl(RoutedEventArgs args)
           at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
           at System.Windows.Controls.Button.OnClick()
           at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
           at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
           at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
           at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
           at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
           at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
           at System.Windows.UIElement.ReRaiseEventAs(RoutedEventArgs args, RoutedEvent newEvent)
           at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
           at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
           at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
           at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
           at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
           at System.Windows.UIElement.RaiseEventImpl(RoutedEventArgs args)
           at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
           at System.Windows.Input.InputManager.ProcessStagingArea()
           at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
           at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
           at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
           at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
           at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
           at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
           at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
           at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
           at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
           at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
           at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
           at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
           at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
           at System.Windows.Threading.Dispatcher.Run()
           at System.Windows.Application.RunInternal(Window window)
           at System.Windows.Application.Run(Window window)
           at System.Windows.Application.Run()
           at AdminConsole2.App.Main() in C:\Users\stephen.verstraete\SourceControl\Airtime\Admin\AdminConsole2\obj\Debug\App.g.cs:line 0
           at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
           at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           at System.Threading.ThreadHelper.ThreadStart()
      InnerException:

    Thursday, February 14, 2008 1:40 AM
  • Hi,

    Thanks for working to track this down. I was just wondering if there's any more information I can give you, or anything I can do that would help to resolve this?

    Sincerely,

    Stephen

    Friday, February 15, 2008 6:44 PM
  • I have found and worked around the issue. I honestly don't understand what the problem was, however I managed to make it work.

     

    I had a property I was calling LayoutSource. The elements in LayoutSource were added into an ObservableCollection and the observable collection was used in databinding. There was no good reason for this left (there were several previously but I refactored the control, however this little piece was missed). The selected element in a combo box is tied to an element to save. For some reason, the second time this was saved it died and gave me that error. Checking the properties on the updated element showed everything to be in order, so I don't quite understand what's going on there. All the elements were still from the correct data contexts.

     

    I removed this extra little layer in databinding and it appears to be working fine. It even meant I could take out the Thread.Sleep.

     

    I essentially removed this little step when the LayoutSource property changed

            private void UpdateLayouts()
            {
                Layouts.Clear();
                Layouts.AddRange(LayoutsSource);
            }

     

    And changed the databinding on the combo box to be LayoutsSource instead of Layouts.

     

    That doesn't really make sense, to me either should really work, unless there's something odd about the way observablecollection works (my class inherited from ObservableCollection<Layouts> and added the single method AddRange, which pretty much looks like List<>.AddRange()).

     

    If anyone has an answer as to why this might be, or I can help figure out what might be causing this, let me know!

     

    Cheers,

    Stephen

     

    Sunday, February 17, 2008 8:08 PM
  • Hi Stephen,

     

    Can you try to reproduce your pb in a small application and share it ?

     

    Mitsu

    Monday, February 18, 2008 7:56 PM
  • There's a lot of steps to reproduce this error, so it will take me a while to create an application for this. I'll spend some time here and there getting it together, but it might take me a couple days.

    Tuesday, February 19, 2008 3:40 PM