Field Value Being Reset on Save

Apr 24, 2011 at 5:26 PM

I'm running into an odd problem in the following code:

        public ActionResult SetVersion( int AssetID, int VersionID )
        {
            VersionedAsset asset = CheckAccessRights(AssetID);
            if( asset == null ) return View("InsufficientRights");

            asset.SelectedID = VersionID;
            DataRepository.Save();

            return View("AssetVersionSet");
        }

When VersionID is different from asset.SelectedID, the new value gets assigned but then immediately overwritten with the old value on the call to Save() (which basically just calls the SaveChanges() method on the entity context). I've watched this happen in the debugger, monitoring the generated property setter method. The "overwriting"/second value setting is being called from external code, not one of my routines.

I tried, for fun, adding a call to Save() before the assignment, thinking that maybe I had an inconsistent state somewhere in my programming model, but that didn't solve the problem. The pre-existing value of SelectedID still ends up overwriting whatever new value I assign to it.

Any thoughts on what might be wrong?

Apr 25, 2011 at 4:23 AM

Some additional info: this problem appears to be related to having two separate entity contexts "in play". I say this because when I tweaked NInject to only allow for the creation of one instance of the entity context ("InSingletonScope()") the problem disappeared.

Which raises a better/different question: how do I avoid this kind of multiple entity context problem in a web app?

Apr 25, 2011 at 4:38 PM

I've done some more research, and now I'm totally confused about why InSingletonScope() "solves" the problem. What I did was add some properties to the entity context object and then the VersionedAsset object that let me track which instance is being accessed whenever the property setting method for VersionedAsset.SelectedID is being called.

Recall that my original problem is that the value of SelectedID gets updated, but then when I call SaveChanges() on the context it gets reset back to its old value. From looking at those instance ID properties I mentioned, it's the same entity context object that's calling the setter, which makes sense, since the SaveChanges() call comes immediately after the SelectedID value is updated.

But it's also the same instance of VersionedAsset being operated on. How can the same instance have two different values simultaneously??

I'm now wondering if this problem isn't due to the relationships among my various entities. Here's how they're laid out:

VersionedAsset derives from Asset
Asset has a property called Owner, which is a relation back to an instance of Member
Member has an ObjectSet<> property of AssetList, one member of which is the instance of VersionedAsset at which I started this description

Is it possible that SaveChanges() is walking the object graph starting from the changed instance of VersionedAsset and then ending back at an older "view" of that same VersionedAsset? Which has the old value for SelectedID which was updated?

I'm asking because in tracing the code through the debugger I can see that SaveChanges() is causing all the properties on the linked entities to be evaluated. And I notice that the generated code for the SelectedID property of VersionedAsset: 

[System.ComponentModel.Browsable(true)]
[EdmScalarPropertyAttribute(EntityKeyProperty = false, IsNullable = true)]
[DataMemberAttribute()]
[System.ComponentModel.DisplayName("SelectedID")]
public virtual int? SelectedID
{
	get { return _selectedID; }
	set
	{
		Widgetsphere.EFCore.EventArgs.ChangingEventArgs<int?> eventArg = new Widgetsphere.EFCore.EventArgs.ChangingEventArgs<int?>(value, "SelectedID");
		if (eventArg.Cancel) return;
		ReportPropertyChanging("SelectedID");
		this.OnPropertyChanging("SelectedID");
		_selectedID = eventArg.Value;
		_modifieddate = DateTime.UtcNow;
		ReportPropertyChanged("SelectedID");
		this.OnPropertyChanged("SelectedID");
	}
}
evaluates eventArg.Cancel to determine whether or not to actually change the backing field's value. This makes me wonder if eventArg.Cancel isn't supposed to be detecting when a property is being updated after its already been changed. If so, maybe it's not working correctly?

Coordinator
Apr 29, 2011 at 1:16 AM
Edited Apr 29, 2011 at 1:17 AM

I know this seems wrong, but comment out the "cancel" checking and recompile. I do not see how this could be an issue. But force the save to always happen. Let me know if there is any change. If there is then we need to investigate if you are catching this event.