实体框架:如果值没有变化,则取消属性更改

时间:2009-01-21 01:16:08

标签: entity-framework

在实体对象上设置属性时,即使该值与以前完全相同,它也会将值保存到数据库中。反正有没有阻止这个?

示例:

如果我加载一个Movie对象并且Title是“A”,如果我再次将Title设置为“A”并且SaveChanges()我希望我不会在SqlProfiler中看到UPDATE语句,但我是。反正有没有阻止这个?

4 个答案:

答案 0 :(得分:5)

是的,你可以改变这个。但是,在当前版本的实体框架中,这样做并非易事。将来会变得更容易。

您看到此行为的原因是因为实体模型的默认代码生成。这是一个代表性的例子:

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();

此默认代码生成是合理的,因为实体框架不知道您打算如何使用这些值的语义。属性中的类型可能具有可比性,也可能不具有可比性,即使它们存在,框架也无法知道您在所有情况下如何使用引用相等与值相等。对于像小数这样的某些值类型,它非常清楚,但从一般意义上说它并不明显。

另一方面,您知道您的代码,并可以自定义一些。麻烦的是这是生成的代码,因此您不能只是进入并编辑它。您需要接管代码生成,或者不必要。那么让我们来看看三个选项。

接管代码生成

这里的基本方法是创建一个T4模板,该模板执行后面的代码,以及来自实体框架的默认代码生成。 Here is one example.此方法的一个优点是the Entity Framework will be moving to T4 generation in the next version,因此您的模板在将来的版本中可能会运行良好。

消除代码生成

第二种方法是完全消除热电联产,do your change tracking support manually, via IPOCO。使用这种方法,您不需要更改代码的生成方式,也不会执行任何代码生成,而是通过实现多个接口为实体框架提供更改跟踪支持。有关更多详细信息,请参阅链接的帖子。

等待

另一个选择是暂时使用实体框架,并等到下一个版本获得您想要的行为。 The next version of the Entity Framework will use T4 by default,因此自定义代码生成非常简单。

答案 1 :(得分:4)

根据MSDN

  

更改对象的状态   无论何时改变都不变   属性设置器被调用。这发生了   即使设定的值是   与当前值相同。之后   调用AcceptAllChanges方法,   state返回Unchanged。通过   默认情况下,调用AcceptAllChanges   在SaveChanges操作期间。

在更新之前,您似乎希望检查Entity对象的属性值,以防止UPDATE语句。

答案 2 :(得分:0)

在通用级别,如果您的实体正在实现INotifyPropertyChanged,那么如果值相同,则不希望触发PropertyChanged事件。所以每个属性都是这样的: -

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

    }

希望这与实体框架相关。

答案 3 :(得分:0)

您可以做的一件事就是使用部分类文件自己包装属性,然后使用您的属性而不是第一个:

public sealed partial class MyEFType {
   public string MyWrappedProperty {
      get {
         return MyProperty;
      }
      set {
         if (value == MyProperty)
            return;
         MyProperty = value;
      }
   }
}

每个属性执行此操作是不切实际的,但如果您需要检测某个特定属性是否已实际更改而不是仅仅已写入,则类似这可行。