カスタム データ クラス インターフェイスの実装 (Entity Framework)

Entity Data Model (EDM) でカスタム データ クラスを使用する場合は、EntityObject および ComplexObject を継承することをお勧めします。EntityObject および ComplexObject を継承できない場合や、フレームワークからの独立性が要求される場合は、Entity Framework のカスタム データ クラス インターフェイスのセットを使用します。EntityObject を継承しない場合、これらのインターフェイスを実装して、EDM でカスタム データ クラスを使用します。実装する具体的なインターフェイスは、カスタム データ クラスとアプリケーションの要件によって異なります。

  • IEntityWithKey
    省略可能です。パフォーマンスの向上のために、エンティティ キーを Object Services に公開します。

    IEntityWithKeyEntityKey プロパティを定義します。Object Services は、EntityKey プロパティを使用して、オブジェクト コンテキスト内のオブジェクトを管理します。

    IEntityWithKey を実装しない場合、関連オブジェクトの読み込み、オブジェクト コンテキストへのオブジェクトのアタッチ、またはキーを必要とする操作でパフォーマンスが著しく低下し、メモリの使用量が増大します。

  • IEntityWithRelationships
    アソシエーションを持つエンティティでは必須です。Object Services でオブジェクト間のリレーションシップを管理できるようにします。

    IEntityWithRelationshipsRelationshipManager プロパティを定義します。Object Services は、RelationshipManager プロパティを使用して、他のオブジェクトに対するリレーションシップを管理するために使用される RelationshipManager にアクセスします。

詳細については、「カスタム データ クラス インターフェイスを実装する方法 (Entity Framework)」を参照してください。

これらのインターフェイスを実装するクラスは、EntityObject を継承するカスタム データ クラスと同様に、次の要件を満たす必要があります。

  • 概念スキーマ定義言語 (CSDL) ファイルで定義された各エンティティ型のオブジェクトが存在する必要があります。

  • 名前空間、クラス、およびデータ プロパティでは、適切な EDM 属性を適用する必要があります。

  • EDM 属性が適用された名前空間、クラス、およびデータ プロパティの名前は、対応する CSDL ファイルの名前と一致する必要があります。

詳細については、「オブジェクトのカスタマイズ (Entity Framework)」を参照してください。

次の例は、Order オブジェクトのインターフェイスの実装に必要なコードを示しています。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 を継承しない複合型オブジェクトによる変更追跡を実装できます。

[!メモ]

オブジェクトのカスタム データ クラス インターフェイスを実装し、さらに 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)

概念

Object Services の概要 (Entity Framework)