사용자 지정 데이터 클래스의 변경 내용 보고(Entity Framework)
개체 서비스는 IEntityChangeTracker 인터페이스를 제공하며, 이 인터페이스는 데이터 클래스에서 데이터 속성 변경을 보고할 때 사용합니다. EntityObject는 IEntityWithChangeTracker의 SetChangeTracker 메서드를 구현합니다. 이 메서드는 개체 서비스에서 호출되며, 변경을 보고하는 데 개체가 사용하는 IEntityChangeTracker 인스턴스를 지정합니다. IEntityChangeTracker에서 지원하는 변경 보고 모델에서는 보류 중인 속성 변경을 보고하고 속성을 설정한 다음 변경이 완료되었음을 보고합니다.
EntityObject에서 상속되지 않은 사용자 지정 데이터 클래스의 변경을 보고하려면 이 클래스가 IEntityWithChangeTracker를 구현해야 합니다. 자세한 내용은 사용자 지정 데이터 클래스 인터페이스 구현(Entity Framework)을 참조하십시오.
변경 내용을 보고할 때 다음 사항을 고려해야 합니다.
속성 값을 설정하기 전에는 속성을 변경 중으로 보고하고, 속성 값을 설정한 후에는 변경됨으로 보고해야 합니다.
EntityKey 속성의 변경을 보고해야 합니다. EntityKey 속성이 설정된 후에는 이 속성을 변경 중으로 보고하는 응용 프로그램 코드는 InvalidOperationException을 발생시킵니다. 그러나 EntityKey 속성이 설정된 후 개체 서비스가 이를 변경해야 하는 경우가 있습니다. 이 속성의 변경을 보고하면 개체 서비스는 이 속성을 설정할 시점을 확인할 수 있습니다.
속성을 변경 중으로 보고하고, 이후에 이를 변경됨으로 보고하지 않을 수 있습니다. 하지만 이 경우, 변경은 추적되지 않습니다.
어떤 속성을 변경 중으로 보고하기 전에 그 속성을 변경됨으로 보고하거나 잘못된 속성 이름이 전달될 경우 InvalidOperationException이 발생합니다. 이는 여러 속성이 변경 중으로 보고되고 이후에 변경됨으로 보고되지 않는 경우에 발생할 수 있습니다. 그 이유는 맨 처음 변경 중으로 보고되었던 속성에 대해 변경된 속성의 유효성을 검사할 때 마지막 속성이 인식되기 때문입니다.
EntityObject 및 ComplexObject에서 상속할 때 속성 변경 보고
사용자 지정 데이터 클래스가 EntityObject 또는 ComplexObject에서 상속하는 경우 속성 변경을 보고하려면 ReportPropertyChanging 및 ReportPropertyChanged 메서드를 호출해야 합니다.
EntityObject에서 상속할 때 속성 변경을 보고하려면
EntityObject의 System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanging(System.String) 메서드를 호출하여 변경 중인 속성의 이름을 전달합니다.
이 메서드는 속성의 현재 값을 캐시하고 이 값이 속성의 원래 값으로 사용됩니다.
속성을 적절히 설정합니다.
EntityObject의 System.Data.Objects.DataClasses.EntityObject.ReportPropertyChanged(System.String) 메서드를 호출하여 변경된 속성의 이름을 전달합니다.
이 메서드는 속성의 보류 중인 변경 내용이 이제 완료되었음을 개체 서비스에 알립니다. 그럼 개체 서비스에서 해당 속성을 수정된 것으로 표시합니다.
ComplexObject에서 상속할 때 속성 변경을 보고하려면
ComplexObject의 System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanging(System.String) 메서드를 호출하여 변경 중인 속성의 이름을 전달합니다. 이 메서드는 속성의 현재 값을 캐시하고 이 값이 속성의 원래 값으로 사용됩니다.
속성을 적절히 설정합니다.
ComplexObject의 System.Data.Objects.DataClasses.ComplexObject.ReportPropertyChanged(System.String) 메서드를 호출하여 변경된 속성의 이름을 전달합니다. 이 메서드는 속성의 보류 중인 변경 내용이 이제 완료되었음을 개체 서비스에 알립니다. 그럼 개체 서비스에서 해당 속성을 수정된 것으로 표시합니다.
다음 예제에서는 Order 개체에서 스칼라 Status 속성을 설정할 때 변경을 보고하는 방법을 보여 줍니다.
<EdmScalarPropertyAttribute(IsNullable:=False)> _
Public Property Status() As Byte
Get
Return _status
End Get
Set(ByVal value As Byte)
If _status <> value Then
ReportPropertyChanging("Status")
_status = value
ReportPropertyChanged("Status")
End If
End Set
End Property
[EdmScalarPropertyAttribute(IsNullable = false)]
public byte Status
{
get
{
return _status;
}
set
{
if (_status != value)
{
ReportPropertyChanging("Status");
_status = value;
ReportPropertyChanged("Status");
}
}
}
IEntityWithChangeTracker 구현 시 속성 변경 보고
사용자 지정 데이터 클래스가 IEntityWithChangeTracker를 구현할 경우, 속성 변경 전후에 IEntityChangeTracker에서 변경 보고 메서드를 호출하여 변경을 제대로 보고해야 합니다.
IEntityWithChangeTracker 구현 시 속성 변경을 보고하려면
EntityMemberChanging 메서드를 호출하여 변경 중인 속성의 이름을 전달합니다. 이 메서드는 속성의 현재 값을 캐시하고 이 값이 속성의 원래 값으로 사용됩니다.
속성을 적절히 설정합니다.
EntityMemberChanged 메서드를 호출하여 변경된 속성의 이름을 전달합니다.
이 메서드는 속성의 보류 중인 변경 내용이 이제 완료되었음을 개체 서비스에 알립니다. 그럼 개체 서비스에서 해당 속성을 수정된 것으로 표시합니다.
복합 형식에 대한 IEntityWithChangeTracker 구현 시 속성 변경을 보고하려면
EntityComplexMemberChanging 메서드를 호출하여 변경된 최상위 엔터티 속성의 이름, 변경된 속성을 포함하는 복합 개체 인스턴스, 복합 형식에 대해 변경된 속성의 이름 등을 전달합니다. 이 메서드는 속성의 현재 값을 캐시하고 이 값이 속성의 원래 값으로 사용됩니다.
속성을 적절히 설정합니다.
EntityComplexMemberChanged 메서드를 호출하여 변경된 최상위 엔터티 속성의 이름, 변경된 속성을 포함하는 복합 개체 인스턴스, 복합 형식에 대해 변경된 속성의 이름 등을 전달합니다. 이 메서드는 속성의 보류 중인 변경 내용이 이제 완료되었음을 개체 서비스에 알립니다. 그럼 개체 서비스에서 해당 속성을 수정된 것으로 표시합니다.
IEntityChangeTracker의 인스턴스를 사용할 수 없는 경우도 있습니다. 이는 개체가 개체 컨텍스트에서 분리된 경우 또는 NoTracking 옵션을 사용하여 쿼리가 실행된 경우 발생할 수 있습니다. 변경 보고 메서드를 호출하기 전에 IEntityChangeTracker 인스턴스를 확인해야 합니다.
다음 예제에서는 파생된 모든 복합 형식의 기본 클래스인 추상 클래스 ComplexTypeChangeTracker를 보여 줍니다. 이 클래스는 복합 형식에 대한 변경 내용 추적을 구현합니다.
' Base class for complex types that implements change tracking.
Public MustInherit Class ComplexTypeChangeTracker
Protected _complexChangeTracker As IEntityChangeTracker = Nothing
Private _rootComplexPropertyName As String
' Gets an IEntityChangeTracker to call for properties change.
' You must do this in order to track changes.
Public Overridable Sub SetComplexChangeTracker( _
ByVal rootComplexPropertyName As String, _
ByVal complexChangeTracker As IEntityChangeTracker)
_rootComplexPropertyName = rootComplexPropertyName
_complexChangeTracker = complexChangeTracker
End Sub
' Protected method that is called before the change for change tracking
' each of the scalar properties in the complex type.
Protected Sub ReportMemberChanging(ByVal scalarPropertyName As String)
If Not _complexChangeTracker Is Nothing Then
_complexChangeTracker.EntityComplexMemberChanging( _
_rootComplexPropertyName, Me, scalarPropertyName)
End If
End Sub
' Protected method that is called after the change for change tracking
' each of the scalar properties in the complex type.
Protected Sub ReportMemberChanged(ByVal scalarPropertyName As String)
If Not _complexChangeTracker Is Nothing Then
_complexChangeTracker.EntityComplexMemberChanged( _
_rootComplexPropertyName, Me, scalarPropertyName)
End If
End Sub
End Class
// Base class for complex types that implements change tracking.
public abstract class ComplexTypeChangeTracker
{
protected IEntityChangeTracker _complexChangeTracker = null;
private string _rootComplexPropertyName;
// Gets an IEntityChangeTracker to call for properties change.
// You must do this in order to track changes.
virtual public void SetComplexChangeTracker(string rootComplexPropertyName, IEntityChangeTracker complexChangeTracker)
{
_rootComplexPropertyName = rootComplexPropertyName;
_complexChangeTracker = complexChangeTracker;
}
// Protected method that is called before the change for change tracking
// each of the scalar properties in the complex type.
protected void ReportMemberChanging(string scalarPropertyName)
{
if (null != _complexChangeTracker)
{
_complexChangeTracker.EntityComplexMemberChanging(_rootComplexPropertyName,
this, scalarPropertyName);
}
}
// Protected method that is called after the change for change tracking
// each of the scalar properties in the complex type.
protected void ReportMemberChanged(string scalarPropertyName)
{
if (null != _complexChangeTracker)
{
_complexChangeTracker.EntityComplexMemberChanged(_rootComplexPropertyName,
this, scalarPropertyName);
}
}
}
다음 예제에서는 이전 예제의 메서드를 사용하여 Order 개체에서 스칼라 Status 속성 설정 시 변경을 보고하는 방법을 보여 줍니다.
<EdmScalarPropertyAttribute()> _
Public Property Comment() As String
Get
Return _comment
End Get
Set(ByVal value As String)
' Validate the value before setting it.
If (value <> Nothing) AndAlso value.Length > 128 Then
Throw New ApplicationException(String.Format( _
My.Resources.propertyNotValidString, _
"Comment", "128"))
End If
If _comment <> value Then
' Report the change if the change tracker exists.
If Not _complexChangeTracker Is Nothing Then
ReportMemberChanging("Comment")
_comment = value
ReportMemberChanged("Comment")
Else
_comment = value
End If
End If
End Set
End Property
[EdmScalarPropertyAttribute()]
public string Comment
{
get
{
return _comment;
}
set
{
// Validate the value before setting it.
if ((value != null) && value.Length > 128)
{
throw new ApplicationException(string.Format(
Properties.Resources.propertyNotValidString,
new string[3] { value, "Comment", "128" }));
}
if (_comment != value)
{
// Report the change if the change tracker exists.
if (_complexChangeTracker != null)
{
ReportMemberChanging("Comment");
_comment = value;
ReportMemberChanged("Comment");
}
else
{
_comment = value;
}
}
}
}