views:

1698

answers:

3

When setting a property on an entity object, it is saving the value to the database even if the value is exactly the same as it was before. Is there anyway to prevent this?

Example:

If I load a Movie object and the Title is "A", if I set the Title to "A" again and SaveChanges() I was hoping that I wouldn't see the UPDATE statement in SqlProfiler but I am. Is there anyway to stop this?

+2  A: 

According to MSDN:

The state of an object is changed from Unchanged to Modified whenever a property setter is called. This occurs even when the value being set is the same as the current value. After the AcceptAllChanges method is called, the state is returned to Unchanged. By default, AcceptAllChanges is called during the SaveChanges operation.

Looks like you'll want to check the value of properties on your Entity objects before you update to prevent the UPDATE statement.

Dave Swersky
An o/r mapper shouldn't force you to babysit change tracking. If c.CompanyName is equal to "Foo Inc" and I set it to "Foo Inc" again, the entity or context/session should understand that it's the same value and not issue an update statement.
Frans Bouma
I wasn't making any statements about whether this is a good thing, just regurgitating their documentation ;)
Dave Swersky
A: 

At a generic level, if your entities are implementing INotifyPropertyChanged, you don't want the PropertyChanged event firing if the value is the same. So each property looks like this :-

    public decimal Value
    {
        get
        {
            return _value;
        }
        set
        {
            if (_value != value)
            {
                _value = value;
                if (_propertyChanged != null) _propertyChanged(this, new PropertyChangedEventArgs("Value"));
            }
        }

    }

Hope that's relevant to Entity Framework.

MrTelly
+2  A: 

Yes, you can change this. Doing so isn't trivial, however, in the current version of the Entity Framework. It will become easier in the future.

The reason you're seeing this behavior is because of the default code generation for the entity model. Here is a representative example:

public global::System.Guid Id
{
    get
    {
        return this._Id;
    }
    set
    {
        // always!
        this.OnIdChanging(value);
        this.ReportPropertyChanging("Id");
        this._Id = global::System.Data.Objects.DataClasses
                               .StructuralObject.SetValidValue(value);
        this.ReportPropertyChanged("Id");
        this.OnIdChanged();
    }
}
private global::System.Guid _Id;
partial void OnIdChanging(global::System.Guid value);
partial void OnIdChanged();

This default code generation is reasonable, because the Entity Framework doesn't know the semantics of how you intend to use the values. The types in the property may or may not be comparable, and even if they are, the framework can't know how you intend to use reference equality versus value equality in all cases. For certain value types like decimal, it's pretty clear, but in a general sense it's not obvious.

You, on the other hand, know your code, and can customize this some. The trouble is that this is generated code, so you can't just go in and edit it. You need to either take over the code generation, or make it unnecessary. So let's look at the three options.

Take over the code generation

The essential approach here is to create a T4 template which does the code behind, and that the default code generation from the Entity Framework. Here is one example. One advantage of this approach is that the Entity Framework will be moving to T4 generation in the next version, so your template will probably work well in future versions.

Eliminate code generation

The second approach would be to eliminate cogeneration altogether, and do your change tracking support manually, via IPOCO. Instead of changing how the code is generated, with this approach you don't do any code generation at all, and instead provide change tracking support to the Entity Framework by implementing several interfaces. See the linked post for more detail.

Wait

Another option is to live with the Entity Framework the way it is for the time being, and wait until the next release to get the behavior you desire. The next version of the Entity Framework will use T4 by default, so customizing the code generation will be very easy.

Craig Stuntz