Поделиться через


Реализация интерфейсов пользовательских классов данных (платформа Entity Framework)

Рекомендуемым способом применения пользовательских классов данных с моделью EDM является наследование от классов EntityObject и ComplexObject. В тех случаях, когда наследование от классов EntityObject и ComplexObject невозможно или необходима более высокая степень независимости от платформы, Entity Framework предоставляет набор интерфейсов пользовательских классов данных. При отсутствии наследования от класса EntityObject необходимо реализовать эти интерфейсы, чтобы использовать с моделью EDM пользовательские классы данных. Реализация конкретных интерфейсов зависит от требований пользовательских классов данных и приложения.

  • IEntityWithKey
    Необязательный. Предоставляет ключ сущности службам объектов для повышения производительности.

    Интерфейс IEntityWithKey определяет свойство EntityKey. Службы объектов используют свойство EntityKey для управления объектами в контексте объекта.

    Если принято решение отказаться от реализации интерфейса IEntityWithKey, то это приведет к снижению производительности и повышению расхода памяти при загрузке связанных объектов, присоединении объектов к контексту объекта и любых других операциях, для которых необходим ключ.

  • IEntityWithRelationships
    Требуется для сущностей с ассоциациями. Задействует службы объектов в управлении связями между объектами.

    Интерфейс IEntityWithRelationships определяет свойство RelationshipManager. Службы объектов используют свойство RelationshipManager для доступа к сущности RelationshipManager, применяемой для управления связями с другими объектами.

Дополнительные сведения см. в разделе Как реализовать пользовательские классы данных (платформа Entity Framework).

Как и пользовательские классы данных, наследованные от класса EntityObject, классы, реализующие эти интерфейсы, должны отвечать следующим требованиям.

  • Должен существовать объект для каждого типа сущности, определенного в CSDL-файле.

  • К пространству имен, классам и свойствам данных необходимо применить соответствующие атрибуты модели EDM.

  • Имена пространства имен, классов и свойств данных с примененными атрибутами модели EDM должны соответствовать именам в соответствующем CSDL-файле.

Дополнительные сведения см. в разделе Настройка объектов (платформа Entity Framework).

В приведенных ниже примерах показан код, необходимый для реализации этих интерфейсов для объекта Order, основанного на таблице SalesOrderHeader.

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, if it is not set.
        ' 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, if it is not set.
        // 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;
    }
}

Сложные типы

Сложные типы — это нескалярные свойства типов сущностей, которые позволяют организовать в сущностях скалярные свойства. Дополнительные сведения см. в разделе Сложный тип (модель EDM). Отслеживание изменений в сложных типах требует написания пользовательского кода для отслеживания изменений. Поэтому рекомендуется применять наследование от EntityObject и ComplexObject, если это возможно. Для объектов сложного типа не существует реализуемых интерфейсов пользовательских классов данных. Однако для реализации отслеживания изменений в сложных типах, не наследованных от класса ComplexObject, можно использовать следующую процедуру.

NoteПримечание.

Если нужно реализовать интерфейсы пользовательских классов данных для объектов и одновременно наследовать от класса ComplexObject, необходимо реализовать пользовательское отслеживание изменений, как показано в следующей процедуре.

Реализация пользовательского отслеживания изменений для объектов сложного типа

  1. Реализуйте интерфейсы пользовательских классов данных для типов сущностей. Дополнительные сведения см. в разделе Как реализовать пользовательские классы данных (платформа Entity Framework).

  2. Убедитесь, что сложные типы верно определены в концептуальном разделе и разделе сопоставлений модели EDM. Дополнительные сведения см. в разделе Сложный тип (модель EDM).

  3. Определите абстрактный базовый класс с именем 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);
            }
        }
    }
    
  4. Определите класс сложного типа, наследуемый от класса ComplexTypeChangeTracker, и примените атрибут EdmComplexTypeAttribute.

    <EdmComplexTypeAttribute(NamespaceName:="Microsoft.Samples.Edm", Name:="OrderInfo")> _
    Partial Public Class OrderInfo
        Inherits ComplexTypeChangeTracker
    
    [EdmComplexTypeAttribute(NamespaceName = "Microsoft.Samples.Edm", Name = "OrderInfo")]
    public partial class OrderInfo : ComplexTypeChangeTracker
    {
    
  5. В классе сложного типа переопределите метод SetComplexChangeTracker.

    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);
    }
    
  6. Реализуйте стандартное отслеживание изменений в скалярных свойствах сложного типа. Дополнительные сведения см. в разделе Отчеты об изменениях в пользовательских классах данных (платформа Entity Framework).

  7. Присвойте сложному свойству в типе сущности атрибут EdmComplexPropertyAttribute и добавьте вызов метода SetComplexChangeTracker для перезапуска объекта отслеживания изменений при изменении этого сложного свойства.

    <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);
            }
        }
    }
    
  8. Повторите шаги 4–7 для каждого сложного свойства.

  9. В реализацию интерфейса System.Data.Objects.DataClasses.IEntityWithChangeTracker.SetChangeTracker(System.Data.Objects.DataClasses.IEntityChangeTracker) для типа сущности вставьте вызов метода SetComplexChangeTracker для установки объекта отслеживания изменений. Повторите эту операцию для каждого сложного свойства в типе.

    ' 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);
    }
    

См. также

Справочник

Генератор модели EDM (EdmGen.exe)

Основные понятия

Общие сведения о службах объектов (платформа Entity Framework)