Implementing Custom Data Class Interfaces (Entity Framework)
The recommended way to use custom data classes with an Entity Data Model (EDM) is to inherit from EntityObject and ComplexObject. For cases when you cannot inherit from EntityObject and ComplexObject or when you need a higher degree of independence from the framework, the Entity Framework provides a set of custom data class interfaces. If you do not inherit from EntityObject, you must implement these interfaces to use custom data classes with an EDM. The specific interfaces that you implement depend on the requirements of your custom data classes and your application.
IEntityWithChangeTracker
Required for change tracking. Enables Object Services to track changes to the object.Object Services provides objects with the IEntityChangeTracker interface to enable objects to report changes. IEntityWithChangeTracker defines the SetChangeTracker method. This method specifies the IEntityChangeTracker used to report changes. For more information, see Reporting Changes in Custom Data Classes (Entity Framework).
IEntityWithKey
Optional. Exposes the entity key to Object Services for improved performance.IEntityWithKey defines the EntityKey property. Object Services uses the EntityKey property to manage objects in the object context.
If you choose not to implement IEntityWithKey, you will see decreased performance and increased memory usage when loading related objects, attaching objects to an object context, or any operation that requires a key.
IEntityWithRelationships
Required for entities with associations. Enables Object Services to manage relationships between objects.IEntityWithRelationships defines the RelationshipManager property. Object Services uses the RelationshipManager property to access the RelationshipManager used to manage relationships to other objects.
For more information, see How to: Implement Custom Data Class Interfaces (Entity Framework).
Like custom data classes that inherit from EntityObject, classes that implement these interfaces must meet the following requirements:
There must be an object for each entity type that is defined in the conceptual schema definition language (CSDL) file.
The namespace, classes, and data properties must have the appropriate EDM attributes applied.
The names of the namespace, classes, and data properties that have EDM attributes applied must match the names in the corresponding CSDL file.
For more information, see Customizing Objects (Entity Framework).
The following example shows the code that is required to implement these interfaces for an Order object, where Order is based on the SalesOrderHeader table.
Dim _changeTracker As IEntityChangeTracker = Nothing
' Specify the IEntityChangeTracker to use for tracking changes.
Private Sub SetChangeTracker(ByVal changeTracker As IEntityChangeTracker) _
Implements IEntityWithChangeTracker.SetChangeTracker
_changeTracker = changeTracker
' Every time the change tracker is set, we must also set all the
' complex type change trackers.
If Not _extendedInfo Is Nothing Then
_extendedInfo.SetComplexChangeTracker("ExtendedInfo", _changeTracker)
End If
End Sub
Dim _entityKey As EntityKey = Nothing
' Define the EntityKey property for the class.
Property EntityKey() As EntityKey Implements IEntityWithKey.EntityKey
Get
Return _entityKey
End Get
Set(ByVal value As EntityKey)
' Set the EntityKey property.
' Report the change if the change tracker exists.
If Not _changeTracker Is Nothing Then
_changeTracker.EntityMemberChanging(StructuralObject.EntityKeyPropertyName)
_entityKey = value
_changeTracker.EntityMemberChanged(StructuralObject.EntityKeyPropertyName)
Else
_entityKey = value
End If
End Set
End Property
Dim _relationships As RelationshipManager = Nothing
' Define a relationship manager for the class.
ReadOnly Property RelationshipManager() As RelationshipManager _
Implements IEntityWithRelationships.RelationshipManager
Get
If _relationships Is Nothing Then
_relationships = RelationshipManager.Create(Me)
End If
Return _relationships
End Get
End Property
IEntityChangeTracker _changeTracker = null;
// Specify the IEntityChangeTracker to use for tracking changes.
void IEntityWithChangeTracker.SetChangeTracker(IEntityChangeTracker changeTracker)
{
_changeTracker = changeTracker;
// Every time the change tracker is set, we must also set all the
// complex type change trackers.
if (_extendedInfo != null)
{
_extendedInfo.SetComplexChangeTracker("ExtendedInfo", _changeTracker);
}
}
EntityKey _entityKey = null;
// Define the EntityKey property for the class.
EntityKey IEntityWithKey.EntityKey
{
get
{
return _entityKey;
}
set
{
// Set the EntityKey property.
// Report the change if the change tracker exists.
if (_changeTracker != null)
{
_changeTracker.EntityMemberChanging(StructuralObject.EntityKeyPropertyName);
_entityKey = value;
_changeTracker.EntityMemberChanged(StructuralObject.EntityKeyPropertyName);
}
else
{
_entityKey = value;
}
}
}
RelationshipManager _relationships = null;
// Define a relationship manager for the class.
RelationshipManager IEntityWithRelationships.RelationshipManager
{
get
{
if (null == _relationships)
_relationships = RelationshipManager.Create(this);
return _relationships;
}
}
Complex Types
Complex types are non-scalar properties of entity types that enable scalar properties to be organized within entities. For more information, see Complex Type (EDM). Tracking changes in complex type objects requires you to write custom change tracking code. Therefore, we recommend inheriting from EntityObject and ComplexObject when possible. There are no custom data class interfaces to implement for complex type objects. However, you can use the following procedure to implement change tracking with complex type objects that do not inherit from ComplexObject.
Note
If you choose to implement custom data class interfaces for objects but also to inherit from ComplexObject, you must still implement custom change tracking as described in the following procedure.
To implement change tracking for complex type objects
Implement custom data interfaces for entity types. For more information, see How to: Implement Custom Data Class Interfaces (Entity Framework).
Ensure that complex types are correctly defined in the conceptual and mapping sections of the EDM. For more information, see Complex Type (EDM).
Define an abstract base class called 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); } } }
Define the complex type class, which inherits from ComplexTypeChangeTracker, and apply the EdmComplexTypeAttribute.
<EdmComplexTypeAttribute(NamespaceName:="Microsoft.Samples.Entity", Name:="OrderInfo")> _ Partial Public Class OrderInfo Inherits ComplexTypeChangeTracker
[EdmComplexTypeAttribute(NamespaceName = "Microsoft.Samples.Entity", Name = "OrderInfo")] public partial class OrderInfo : ComplexTypeChangeTracker {
In the complex type class, override the SetComplexChangeTracker method.
Public Overrides Sub SetComplexChangeTracker(ByVal rootComplexPropertyName As String, _ ByVal changeTracker As IEntityChangeTracker) ' Call SetChangeTracker on the base class to set the change tracker ' and the name of the root complex type property on the entity. MyBase.SetComplexChangeTracker(rootComplexPropertyName, changeTracker) End Sub
override public void SetComplexChangeTracker(string rootComplexPropertyName, IEntityChangeTracker changeTracker) { // Call SetChangeTracker on the base class to set the change tracker // and the name of the root complex type property on the entity. base.SetComplexChangeTracker(rootComplexPropertyName, changeTracker); }
Implement standard change tracking on the scalar properties of the complex type. For more information, see Reporting Changes in Custom Data Classes (Entity Framework).
Apply the EdmComplexPropertyAttribute to the complex property in the entity type, and add a call to SetComplexChangeTracker to reset the change tracker when the complex property changes.
<EdmComplexPropertyAttribute()> _ Public Property ExtendedInfo() As OrderInfo Get Return _extendedInfo End Get Set(ByVal value As OrderInfo) ' For a complex type any changes in the complex type ' properties all get tracked together. ' The change tracker may be Nothing during object materialization. If Not _changeTracker Is Nothing Then ' Since this is a complex property, we need to reset the change ' tracker on the complex type. If Not _extendedInfo Is Nothing Then ' Reset the change tracker. _extendedInfo.SetComplexChangeTracker("ExtendedInfo", Nothing) End If ' Report the change. _changeTracker.EntityMemberChanging("ExtendedInfo") _extendedInfo = value _changeTracker.EntityMemberChanging("ExtendedInfo") Else _extendedInfo = value End If ' Rest the change tracker. Complex type property cannot be Nothing. If Not _extendedInfo Is Nothing Then _extendedInfo.SetComplexChangeTracker("ExtendedInfo", _changeTracker) End If End Set End Property
[EdmComplexPropertyAttribute()] public OrderInfo ExtendedInfo { get { return _extendedInfo; } set { // For a complex type any changes in the complex type // properties all get tracked together. // The change tracker may be null during object materialization. if (_changeTracker != null) { // Since this is a complex property, we need to reset the change // tracker on the complex type. if (_extendedInfo != null) { // Reset the change tracker. _extendedInfo.SetComplexChangeTracker("ExtendedInfo", null); } // Report the change. _changeTracker.EntityMemberChanging("ExtendedInfo"); _extendedInfo = value; _changeTracker.EntityMemberChanged("ExtendedInfo"); } else { _extendedInfo = value; } // Reset the change tracker. Complex type property cannot be null. if (_extendedInfo != null) { _extendedInfo.SetComplexChangeTracker("ExtendedInfo", _changeTracker); } } }
Repeat steps 4-7 for each complex property.
In the System.Data.Objects.DataClasses.IEntityWithChangeTracker.SetChangeTracker(System.Data.Objects.DataClasses.IEntityChangeTracker) implementation for the entity type, insert a call to SetComplexChangeTracker to set the change tracker. Do this once for each complex property in the type.
' Every time the change tracker is set, we must also set all the ' complex type change trackers. If Not _extendedInfo Is Nothing Then _extendedInfo.SetComplexChangeTracker("ExtendedInfo", _changeTracker) End If
// Every time the change tracker is set, we must also set all the // complex type change trackers. if (_extendedInfo != null) { _extendedInfo.SetComplexChangeTracker("ExtendedInfo", _changeTracker); }