如何使用ObjectWithChangeTracker通知子对象修改父对象

时间:2012-01-04 18:13:49

标签: c# self-tracking-entities

使用Ado.net自我跟踪实体生成器创建对象以维护状态跟踪器。对象是用户,培训师。 Trainer是User中的子对象。在Trainer中修改信息时,其状态将更改为已修改。但用户对象仍未更改。我的要求是,当修改子对象时,它必须与父对象保持密切关系。

User.cs

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.Serialization;

namespace ControlLibrary
{
    [DataContract(IsReference = true)]
    [KnownType(typeof(Trainer))]
    public partial class User: IObjectWithChangeTracker, INotifyPropertyChanged
    {
        #region Primitive Properties

        [DataMember]
        public int UserId
        {
            get { return _userId; }
            set
            {
                if (_userId != value)
                {
                    if (ChangeTracker.ChangeTrackingEnabled && ChangeTracker.State != ObjectState.Added)
                    {
                        throw new InvalidOperationException("The property 'UserId' is part of the object's key and cannot be changed. Changes to key properties can only be made when the object is not being tracked or is in the Added state.");
                    }
                    _userId = value;
                    OnPropertyChanged("UserId");
                }
            }
        }
        private int _userId;

        [DataMember]
        public string UserName
        {
            get { return _userName; }
            set
            {
                if (_userName != value)
                {
                    _userName = value;
                    OnPropertyChanged("UserName");
                }
            }
        }
        private string _userName;

        #endregion
        #region Navigation Properties

        [DataMember]
        public Trainer Trainer
        {
            get { return _trainer; }
            set
            {
                if (!ReferenceEquals(_trainer, value))
                {
                    var previousValue = _trainer;
                    _trainer = value;
                    FixupTrainer(previousValue);
                    OnNavigationPropertyChanged("Trainer");
                }
            }
        }
        private Trainer _trainer;

        #endregion
        #region ChangeTracking

        protected virtual void OnPropertyChanged(String propertyName)
        {
            if (ChangeTracker.State != ObjectState.Added && ChangeTracker.State != ObjectState.Deleted)
            {
                ChangeTracker.State = ObjectState.Modified;
            }
            if (_propertyChanged != null)
            {
                _propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected virtual void OnNavigationPropertyChanged(String propertyName)
        {
            if (_propertyChanged != null)
            {
                _propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged{ add { _propertyChanged += value; } remove { _propertyChanged -= value; } }
        private event PropertyChangedEventHandler _propertyChanged;
        private ObjectChangeTracker _changeTracker;

        [DataMember]
        public ObjectChangeTracker ChangeTracker
        {
            get
            {
                if (_changeTracker == null)
                {
                    _changeTracker = new ObjectChangeTracker();
                    _changeTracker.ObjectStateChanging += HandleObjectStateChanging;
                }
                return _changeTracker;
            }
            set
            {
                if(_changeTracker != null)
                {
                    _changeTracker.ObjectStateChanging -= HandleObjectStateChanging;
                }
                _changeTracker = value;
                if(_changeTracker != null)
                {
                    _changeTracker.ObjectStateChanging += HandleObjectStateChanging;
                }
            }
        }

        private void HandleObjectStateChanging(object sender, ObjectStateChangingEventArgs e)
        {
            if (e.NewState == ObjectState.Deleted)
            {
                ClearNavigationProperties();
            }
        }

        protected bool IsDeserializing { get; private set; }

        [OnDeserializing]
        public void OnDeserializingMethod(StreamingContext context)
        {
            IsDeserializing = true;
        }

        [OnDeserialized]
        public void OnDeserializedMethod(StreamingContext context)
        {
            IsDeserializing = false;
            ChangeTracker.ChangeTrackingEnabled = true;
        }

        protected virtual void ClearNavigationProperties()
        {
            Trainer = null;
        }

        #endregion
        #region Association Fixup

        private void FixupTrainer(Trainer previousValue)
        {
            // This is the principal end in an association that performs cascade deletes.
            // Update the event listener to refer to the new dependent.
            if (previousValue != null)
            {
                ChangeTracker.ObjectStateChanging -= previousValue.HandleCascadeDelete;
            }

            if (Trainer != null)
            {
                ChangeTracker.ObjectStateChanging += Trainer.HandleCascadeDelete;
            }

            if (IsDeserializing)
            {
                return;
            }

            if (previousValue != null && ReferenceEquals(previousValue.User, this))
            {
                previousValue.User = null;
            }

            if (Trainer != null)
            {
                Trainer.User = this;
            }

            if (ChangeTracker.ChangeTrackingEnabled)
            {
                if (ChangeTracker.OriginalValues.ContainsKey("Trainer")
                    && (ChangeTracker.OriginalValues["Trainer"] == Trainer))
                {
                    ChangeTracker.OriginalValues.Remove("Trainer");
                }
                else
                {
                    ChangeTracker.RecordOriginalValue("Trainer", previousValue);
                    // This is the principal end of an identifying association, so the dependent must be deleted when the relationship is removed.
                    // If the current state of the dependent is Added, the relationship can be changed without causing the dependent to be deleted.
                    if (previousValue != null && previousValue.ChangeTracker.State != ObjectState.Added)
                    {
                        previousValue.MarkAsDeleted();
                    }
                }
                if (Trainer != null && !Trainer.ChangeTracker.ChangeTrackingEnabled)
                {
                    Trainer.StartTracking();
                }
            }
        }

        #endregion
    }
}

Trainer.cs文件是

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated from a template.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.Serialization;

namespace ControlLibrary
{
    [DataContract(IsReference = true)]
    [KnownType(typeof(User))]
    public partial class Trainer: IObjectWithChangeTracker, INotifyPropertyChanged
    {
        #region Primitive Properties

        [DataMember]
        public int TrainerId
        {
            get { return _trainerId; }
            set
            {
                if (_trainerId != value)
                {
                    if (ChangeTracker.ChangeTrackingEnabled && ChangeTracker.State != ObjectState.Added)
                    {
                        throw new InvalidOperationException("The property 'TrainerId' is part of the object's key and cannot be changed. Changes to key properties can only be made when the object is not being tracked or is in the Added state.");
                    }
                    if (!IsDeserializing)
                    {
                        if (User != null && User.UserId != value)
                        {
                            User = null;
                        }
                    }
                    _trainerId = value;
                    OnPropertyChanged("TrainerId");
                }
            }
        }
        private int _trainerId;

        [DataMember]
        public int UserId
        {
            get { return _userId; }
            set
            {
                if (_userId != value)
                {
                    _userId = value;
                    OnPropertyChanged("UserId");
                }
            }
        }
        private int _userId;

        [DataMember]
        public Nullable<bool> IsFloorTrainer
        {
            get { return _isFloorTrainer; }
            set
            {
                if (_isFloorTrainer != value)
                {
                    _isFloorTrainer = value;
                    OnPropertyChanged("IsFloorTrainer");
                }
            }
        }
        private Nullable<bool> _isFloorTrainer;

        #endregion
        #region Navigation Properties

        [DataMember]
        public User User
        {
            get { return _user; }
            set
            {
                if (!ReferenceEquals(_user, value))
                {
                    if (ChangeTracker.ChangeTrackingEnabled && ChangeTracker.State != ObjectState.Added && value != null)
                    {
                        // This the dependent end of an identifying relationship, so the principal end cannot be changed if it is already set,
                        // otherwise it can only be set to an entity with a primary key that is the same value as the dependent's foreign key.
                        if (TrainerId != value.UserId)
                        {
                            throw new InvalidOperationException("The principal end of an identifying relationship can only be changed when the dependent end is in the Added state.");
                        }
                    }
                    var previousValue = _user;
                    _user = value;
                    FixupUser(previousValue);
                    OnNavigationPropertyChanged("User");
                }
            }
        }
        private User _user;

        #endregion
        #region ChangeTracking

        protected virtual void OnPropertyChanged(String propertyName)
        {
            if (ChangeTracker.State != ObjectState.Added && ChangeTracker.State != ObjectState.Deleted)
            {
                ChangeTracker.State = ObjectState.Modified;
            }
            if (_propertyChanged != null)
            {
                _propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected virtual void OnNavigationPropertyChanged(String propertyName)
        {
            if (_propertyChanged != null)
            {
                _propertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged{ add { _propertyChanged += value; } remove { _propertyChanged -= value; } }
        private event PropertyChangedEventHandler _propertyChanged;
        private ObjectChangeTracker _changeTracker;

        [DataMember]
        public ObjectChangeTracker ChangeTracker
        {
            get
            {
                if (_changeTracker == null)
                {
                    _changeTracker = new ObjectChangeTracker();
                    _changeTracker.ObjectStateChanging += HandleObjectStateChanging;
                }
                return _changeTracker;
            }
            set
            {
                if(_changeTracker != null)
                {
                    _changeTracker.ObjectStateChanging -= HandleObjectStateChanging;
                }
                _changeTracker = value;
                if(_changeTracker != null)
                {
                    _changeTracker.ObjectStateChanging += HandleObjectStateChanging;
                }
            }
        }

        private void HandleObjectStateChanging(object sender, ObjectStateChangingEventArgs e)
        {
            if (e.NewState == ObjectState.Deleted)
            {
                ClearNavigationProperties();
            }
        }

        protected bool IsDeserializing { get; private set; }

        [OnDeserializing]
        public void OnDeserializingMethod(StreamingContext context)
        {
            IsDeserializing = true;
        }

        [OnDeserialized]
        public void OnDeserializedMethod(StreamingContext context)
        {
            IsDeserializing = false;
            ChangeTracker.ChangeTrackingEnabled = true;
        }

        // This entity type is the dependent end in at least one association that performs cascade deletes.
        // This event handler will process notifications that occur when the principal end is deleted.
        internal void HandleCascadeDelete(object sender, ObjectStateChangingEventArgs e)
        {
            if (e.NewState == ObjectState.Deleted)
            {
                this.MarkAsDeleted();
            }
        }

        protected virtual void ClearNavigationProperties()
        {
            User = null;
        }

        #endregion
        #region Association Fixup

        private void FixupUser(User previousValue)
        {
            if (IsDeserializing)
            {
                return;
            }

            if (previousValue != null && ReferenceEquals(previousValue.Trainer, this))
            {
                previousValue.Trainer = null;
            }

            if (User != null)
            {
                User.Trainer = this;
                TrainerId = User.UserId;
            }

            if (ChangeTracker.ChangeTrackingEnabled)
            {
                if (ChangeTracker.OriginalValues.ContainsKey("User")
                    && (ChangeTracker.OriginalValues["User"] == User))
                {
                    ChangeTracker.OriginalValues.Remove("User");
                }
                else
                {
                    ChangeTracker.RecordOriginalValue("User", previousValue);
                }
                if (User != null && !User.ChangeTracker.ChangeTrackingEnabled)
                {
                    User.StartTracking();
                }
            }
        }

        #endregion
    }
}

1 个答案:

答案 0 :(得分:0)

你不想这样做。这意味着当你有更复杂的对象图并且某个对象的实例已经改变时,这将被传播到位于上面的所有父对象。这仍然不是一个问题。但是,对于持久化实体的ObjectContext应用更改时,FrameWork还会更新所有父项(当您的目标是将更改传播到父项的ChangeTracker时 - > {{{ 1}}是FrameWork用于检测更改并向数据库发送更新,插入或删除查询的对象。

实体框架不包括这种&#34;级联&#34;自我跟踪实体本身的信息。

我们需要类似的功能。轻松检测顶级&#34;对象,如果下面有任何变化。我们制作了一个递归方法来检查所有基础实体和ChangeTracker的{​​{1}}。请注意:您可能不仅需要查看State,还需要查看ChangeTrackersentity.ChangeTracker.State以查看是否在导航属性中添加或删除了任何实体(基本上也是更改)。< / p>

另一种选择是在每个实体上包含一个简单的枚举(清除,修改,添加,删除等等),并且在进行更改时更新实体上的Enum变量和&#34; parent&# 34;以上。这样你就不会干扰ChangeTracker,我也不会过多地干扰它。

希望这有帮助。