LinqConnect Documentation
In This Topic
    Comparing Original and Current Entity State
    In This Topic

    Generally, to know which entities were modified, one should store copies of all the entities. When an entity is attached to a DataContext (is read from the database or inserted to it) - a copy should be created. User does not have a reference to this copy, unlike the original entity, so this copy cannot be modified and is always in an unchanged state. When performing submit, each copy is compared with the current entity, and it is determined whether the entity must be updated in the database, and which entity properties must be updated. After database update, the copy is updated to the current state and is used in the next submit operation if such is performed.

    If an entity has no key, it cannot be cached and change tracking is not enabled for such entity. LinqConnect does not allow modifications of such entities. An exception is raised when such entity is created or deleted, and updates of such entity are ignored.

    However, creating and storing a copy for each retrieved entity is costly, and in addition you need to compare all entities with their copy when performing submit. Performance overhead can be even worse when we retrieved the whole table and updated only few entities.

    That's why it is better to store only copies of modified entities. For example use special events that occur when an entity is changed. LinqConnect uses the INotifyPropertyChanging interface from the System.ComponentModel namespace. This member has the only member - the PropertyChanging event, which should be raised right before the tracked property is modified. The subscribed handler of this event, generated by LinqConnect can process it and create an entity copy.

    For example, all entities, generated by the LinqConnect template, implement this interface and each mapped property setter launches the PropertyChanging event just before modifying the corresponding private field:


    public partial class Product : INotifyPropertyChanging, INotifyPropertyChanged    
    {
     
        private static PropertyChangingEventArgs emptyChangingEventArgs = 
            new PropertyChangingEventArgs(System.String.Empty);
        
        ...  
     
        private string _ProductName;
     
        [Column(Storage = "_ProductName", CanBeNull = false, DbType = "VARCHAR(50) NOT NULL")]
        public string ProductName
        {
            get { ... }
            set
            {
                if (this._ProductName != value)
                {
                    this.OnProductNameChanging(value);
                    this.SendPropertyChanging();
                    this._ProductName = value;
                    ...
                }
            }
        }
      
        ...
     
        public event PropertyChangingEventHandler PropertyChanging;
     
        ...
     
        protected virtual void SendPropertyChanging()
        {
            if (this.PropertyChanging != null)
                this.PropertyChanging(this, emptyChangingEventArgs);
        }
     
        ...
     
    }
    
    Public Partial Class Product
        Implements INotifyPropertyChanging, INotifyPropertyChanged
     
        Private Shared emptyChangingEventArgs As PropertyChangingEventArgs = _
            New PropertyChangingEventArgs(System.String.Empty)
     
        ... 
        
        Private _ProductName As String
        
        ...
         
        <Column(Storage := "_ProductName", CanBeNull := false, DbType := "VARCHAR(50) NOT NULL")> _
        Public Property ProductName As String
            Get
                ...
            End Get
            Set
     
                If (Object.Equals(Me._ProductName, value) = false) Then
                    Me.OnProductNameChanging(value)
                    Me.SendPropertyChanging()
                    Me._ProductName = value
                     
                    ...
                    
                End If
            End Set
        End Property
     
        ...
     
        Public Event PropertyChanging As PropertyChangingEventHandler _
            Implements System.ComponentModel.INotifyPropertyChanging.PropertyChanging
     
        ... 
    
        Protected Overridable Sub SendPropertyChanging()
            If (Not Me.PropertyChangingEvent Is Nothing) Then
                RaiseEvent PropertyChanging(Me, emptyChangingEventArgs)
            End If
        End Sub
     
        ... 
        
    End Class
    

    And now let's illustrate using this interface by the following example:


    Product shakespeareWorks = context.Products.Where(p => p.ProductID == 7007).Single();
    shakespeareWorks.ProductName = "Shakespeare W. Shakespeare's dramatic works";
    Dim shakespeareWorks As Product = context.Products.Where(Function(p) p.ProductID = 7007).[Single]()
    shakespeareWorks.ProductName = "Shakespeare W. Shakespeare's dramatic works"
    

    When we retrieve the product, the context starts tracking it. However the context knows that the Product class implements INotifyPropertyChanging, so it subscribes to the PropertyChanging event and does not create a copy at this moment.

    Only when we change ProductName (or any other property), SendPropertyChanging is called and LinqConnect runtime receives the PropertyChanging event, creates a copy and marks 'shakespeareWorks' to be checked for changes when submitting modified entities.

    Note:
    Besides INotifyPropertyChanging, LinqConnect entities implement the INotifyPropertyChanged interface. This interface is not used by LinqConnect runtime. It is implemented to ease binding.