チュートリアル: 自己追跡エンティティのシリアル化 (Entity Framework)

このトピックのチュートリアルでは、エンティティ グラフを返す一連の操作を Windows Communication Foundation (WCF) サービスで公開するシナリオを示します。 次に、クライアント アプリケーションでそのグラフを操作し、Entity Framework を使用してデータベースへの更新を検証および保存するサービス操作に変更内容を送信します。 詳細については、「自己追跡エンティティの使用」を参照してください。

通常、自己追跡エンティティ型を含むプロジェクトから、モデル プロジェクトを分離する必要が生じます。 その場合、クライアントでは、エンティティ型プロジェクトだけを含める必要があります。

この分離を行う 1 つの方法として、自己追跡エンティティ型をモデルから分離し、エンティティ型を生成するテンプレートを別のクラス ライブラリに移動します。 .edmx ファイルの場所は、そのメタデータにアクセスするために、自己追跡エンティティ テンプレートの中に含める必要があります。 元のプロジェクトのテンプレートを他のプロジェクトに移動する場合は、エディターでテンプレート ファイルを開き、inputFile 文字列を .edmx ファイルの相対的な位置に変更する必要があります。 テンプレートの操作の詳細については、「ADO.NET Self-Tracking Entity Template」を参照してください。

また、モデルからエンティティ型を分離する方法として、元のプロジェクト内にテンプレート ファイルを残したままそのテンプレートのコード生成を無効にする方法もあります。 別のプロジェクトからテンプレートに対してリンクを生成すると、元のプロジェクトではなくその別のプロジェクトでコードが生成されます。 プロジェクトにリンクとして項目を追加すると、その項目の実際の内容は、元のプロジェクトが示している場所に保持されます。 エンティティ型をモデルから分離するこの方法について、このチュートリアルで説明します。

このチュートリアルでは次の操作を行います。

  • School ベースのモデルを含むクラス ライブラリ プロジェクトを作成します。

  • ADO.NET Self-Tracking Entity Generator テンプレートを使用して、エンティティ型、型指定された ObjectContext、およびオーバーロードされた ApplyChanges メソッドを含む拡張クラスを生成します。

  • 最初のプロジェクトで作成された自己追跡エンティティ型テンプレートにリンクするクラス ライブラリ プロジェクトを作成します。

  • エンティティ グラフを返す一連の操作を公開し、Entity Framework を使用してクライアントに対して行われた変更をデータベースに適用する、WCF サービスを作成します。

  • WCF サービスで公開されている操作を使用して、グラフを操作して変更内容を送信するクライアント アプリケーション (コンソールおよび Windows Presentation Foundation [WPF]) を作成します。

Ee789839.note(ja-jp,VS.100).gif注 :
STESchoolModelExample は、MSDN コード ギャラリーの Entity Framework ドキュメントのサンプルのサイトでダウンロードできます。

自己追跡エンティティとオブジェクト コンテキスト クラスを含むクラス ライブラリ プロジェクトを作成するには

  1. 新しいクラス ライブラリ プロジェクトを作成します。 プロジェクトとソリューションの名前に「STESchoolModel」と入力します。

  2. プロジェクトに追加された既定のソース コード ファイルを削除します。

  3. Entity Data Model ウィザードを使用して、School データベース内の DepartmentCourseOnlineCourse、および OnsiteCourse テーブルに基づいてモデルを生成します。 詳細については、「School モデル」を参照してください。

  4. ADO.NET Entity Data Model Designer (エンティティ デザイナー) で .edmx ファイルを開きます。

  5. Walkthrough: Mapping Inheritance - Table-per-Type」の継承マッピングの手順に従います。

  6. エンティティ デザイナー画面で空の領域を右クリックし、[コード生成項目の追加] をポイントして、[ADO.NET Self-Tracking Entity Generator] をクリックします。 既定のテンプレート名を「SchoolModel」に変更します。

    Ee789839.note(ja-jp,VS.100).gif注 :
    テンプレート ファイルがプロジェクトに追加されると、テンプレートの作成元を信頼する場合にのみテンプレートを受け入れるかどうかを尋ねるセキュリティ警告が表示されることがあります。[承諾] をクリックします。

  7. SchoolModel.Context.tt フォルダーと SchoolModel.tt フォルダーがプロジェクトに追加されます。 SchoolModel.Context.tt フォルダーには、型指定された ObjectContext と、オーバーロードされた ApplyChanges メソッドを含む拡張クラスを定義する、2 つのファイルがあります。 SchoolModel.tt フォルダーには、エンティティ型を定義するファイルと、自己追跡エンティティによって使用される変更追跡ロジックを含むヘルパー クラスを定義するファイルがあります。

    次の 2 つの手順では、このプロジェクトでコード生成を無効にする方法を示しています。 コード生成は、STESchoolModelTypes クラス ライブラリの型と、STESchoolModelService 内のオブジェクト コンテキストに対して、後で有効にします。

  8. SchoolModel.tt を選択します。 [プロパティ] ウィンドウで、CustomTool プロパティの TextTemplatingFileGenerator をクリアします。 SchoolModel.tt フォルダー内のファイルを削除します。

  9. SchoolModel.Context.tt を選択します。 [プロパティ] ウィンドウで、CustomTool プロパティの値をクリアします。 SchoolModel.Context.tt フォルダー内のファイルを削除します。

    Visual Basic プロジェクトを使用している場合は、必要に応じて、ソリューション エクスプローラー[すべてのファイルを表示] をクリックして、プロジェクト内のすべてのファイルを表示します。

  10. プロジェクトをコンパイルします。

自己追跡型テンプレートにリンクするクラス ライブラリ プロジェクトを作成するには

  1. 前のプロジェクトと同じソリューションで、STESchoolModelTypes という名前の新しいクラス ライブラリ プロジェクトを作成します。

  2. プロジェクトに追加された既定のソース コード ファイルを削除します。

  3. 自己追跡エンティティ型がこのソリューションで生成されるように、SchoolModel.tt ファイルへのリンクを追加します。 ソリューション エクスプローラーで、[STESchoolModelTypes] を右クリックし、[追加] をクリックして [既存の項目] をクリックします。

  4. [既存項目の追加] ダイアログ ボックスで、STESchoolModel プロジェクトを参照し、[SchoolModel.tt] をクリックします (Enter キーを押さないでください)。 [追加] の一覧で、[リンクとして追加] をクリックします。

  5. System.Runtime.Serialization ライブラリへの参照を追加します。 このライブラリは、シリアル化可能なエンティティ型で使用される WCF DataContract および DataMember 属性に必要です。

  6. プロジェクトをコンパイルします。

WCF サービス アプリケーション プロジェクトを作成して構成するには

  1. 前のプロジェクトと同じソリューションで、STESchoolModelService という名前の WCF サービス アプリケーション プロジェクトを作成します。

  2. System.Data.Entity.dll への参照を追加します。

  3. STESchoolModel および STESchoolModelTypes プロジェクトへの参照を追加します。

  4. このソリューションでコンテキスト型が生成されるように、SchoolModel.Context.tt ファイルへのリンクを追加します。 ソリューション エクスプローラーで、[STESchoolModelService] を右クリックし、[追加] をクリックして [既存の項目] をクリックします。

  5. [既存項目の追加] ダイアログ ボックスで、STESchoolModel プロジェクトを参照し、[SchoolModel.Context.tt] をクリックします (Enter キーを押さないでください)。 [追加] の一覧で、[リンクとして追加] をクリックします。

  6. SchoolModel.Context.tt ファイルの [プロパティ] ウィンドウで、[カスタム ツールの名前空間] プロパティに「STESchoolModelTypes」と入力します。 これによって、自己追跡エンティティ型の名前空間と同じ名前空間にオブジェクト コンテキスト型が追加されます。これは必須です。

  7. (Visual Basic のみ) SchoolModel.Context.tt ファイルから生成されたソース ファイルに Import STESchoolModelTypes を追加します。 SchoolModel.Context.tt ファイルを開き、Imports System という文字列を探します。 他のインポートの後に Import STESchoolModelTypes を追加します。 生成されたソース ファイルに、この名前空間が含まれます。

  8. Entity Framework ランタイムがメタデータを検出できるように、Web.config ファイルに接続文字列を追加します。 STESchoolModel プロジェクトの app.config ファイルを開きます。 connectionStrings 要素をコピーして、Web.config ファイルの configuration 要素の子要素として追加します。

  9. サービス インターフェイス ファイルを開きます。 既定で、ファイルの名前は IService1 です。

  10. 自己追跡エンティティが定義されている名前空間 STESchoolModelTypes を追加します。

  11. サービス インターフェイス定義を次のコードに置き換えます。

    <ServiceContract()> _
    Public Interface IService1
        <OperationContract()> _
        Sub UpdateDepartment(ByVal updated As Department)
        <OperationContract()> _
        Function GetDepartments() As List(Of Department)
    End Interface
    
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        void UpdateDepartment(Department updated);
        [OperationContract]
        List<Department> GetDepartments();
    }
    
  12. サービス ソース コードを開きます。 このファイルの名前は、既定では、Service1.srv.cs または Service1.srv.vb となります。

  13. 自己追跡エンティティが定義されている名前空間 STESchoolModelTypes を追加します。

  14. (Visual Basic のみ) Imports STESchoolModelService.STESchoolModelTypesService1.srv.cs ファイルに追加します。

  15. サービス クラス定義を次のコードに置き換えます。

Ee789839.Important(ja-jp,VS.100).gif 注 :
変更を適用する前に、更新されるオブジェクトに対して必ず検証を実行してください。

Public Class Service1
    Implements IService1
    ''' <summary>
    ''' Updates department and its related courses. 
    ''' </summary>
    Public Sub UpdateDepartment(ByVal updated As Department) Implements IService1.UpdateDepartment
        Using context As New STESchoolModelTypes.SchoolEntities()
            Try
                ' Perform validation on the updated order before applying the changes.

                ' The ApplyChanges method examines the change tracking information 
                ' contained in the graph of self-tracking entities to infer the set of operations
                ' that need to be performed to reflect the changes in the database. 
                context.Departments.ApplyChanges(updated)

                context.SaveChanges()
            Catch ex As UpdateException
                ' To avoid propagating exception messages that contain sensitive data to the client tier, 
                ' calls to ApplyChanges and SaveChanges should be wrapped in exception handling code.
                Throw New InvalidOperationException("Failed to update the department. Try your request again.")
            End Try
        End Using
    End Sub

    ''' <summary>
    ''' Gets all the departments and related courses. 
    ''' </summary>
    Public Function GetDepartments() As List(Of Department) Implements IService1.GetDepartments
        Using context As New STESchoolModelTypes.SchoolEntities()
            ' Use System.Data.Objects.ObjectQuery(T).Include to eagrly load the related courses.
            Return context.Departments.Include("Courses").OrderBy(Function(d) d.Name).ToList()
        End Using
    End Function

End Class
public class Service1 : IService1
{
    /// <summary>
    /// Updates department and its related courses. 
    /// </summary>
    public void UpdateDepartment(Department updated)
    {
        using (SchoolEntities context =
            new SchoolEntities())
        {
            try
            {
                // Perform validation on the updated order before applying the changes.

                // The ApplyChanges method examines the change tracking information 
                // contained in the graph of self-tracking entities to infer the set of operations
                // that need to be performed to reflect the changes in the database. 
                context.Departments.ApplyChanges(updated);
                context.SaveChanges();

            }
            catch (UpdateException ex)
            {
                // To avoid propagating exception messages that contain sensitive data to the client tier, 
                // calls to ApplyChanges and SaveChanges should be wrapped in exception handling code.
                throw new InvalidOperationException("Failed to update the department. Try your request again.");
            }
        }
    }

    /// <summary>
    /// Gets all the departments and related courses. 
    /// </summary>
    public List<Department> GetDepartments()
    {
        using (SchoolEntities context = new SchoolEntities())
        {
            // Use System.Data.Objects.ObjectQuery(T).Include to eagrly load the related courses.
            return context.Departments.Include("Courses").OrderBy(d => d.Name).ToList();
        }
    }

}

コンソール クライアント アプリケーションを使用してサービスをテストするには

  1. コンソール アプリケーションを作成します。 前のプロジェクトと同じソリューションで、プロジェクト名に「STESchoolModelTest」と入力します。

  2. STEASchoolModelService サービスへの参照を追加します。 サービスへの参照を追加するには、ソリューション エクスプローラーで参照フォルダーを右クリックし、[サービス参照の追加] をクリックします。

    既定では、WCF によって、IEnumerable コレクションを返すプロキシが生成されます。 STESchoolModelServiceGetDepartments メソッドは List を返すため、適切な戻り値の型を指定するようにサービスを構成する必要があります。

  3. サービス名 (ServiceReference1) を右クリックし、[サービス参照の構成] をクリックします。 [サービス参照の構成] ダイアログ ボックスで、[コレクション型] ボックスの一覧から [System.Collections.Generic.List] 型を選択します。

  4. STESchoolModelTypes プロジェクトへの参照を追加します。

  5. app.config ファイルを開き、ファイルに接続文字列を追加します。 STESchoolModel プロジェクトの app.config ファイルを開き、connectionStrings 要素をコピーして、Web.config ファイルの configuration 要素の子要素として追加します。

  6. main 関数を含んでいるファイルを開きます。 STESchoolModelTest.ServiceReference1 名前空間および STESchoolModelTypes 名前空間 (自己追跡型が定義されている名前空間) を含めます。

  7. main 関数に次のコードを貼り付けます。 このコードには、次の手順で定義するメソッドへの関数呼び出しが含まれています。

    ' Note, the service's GetDepartments method returns System.Collections.Generic.List.
    ' By default, when WCF generates a proxy the return collection types are converted to IEnumerable.
    ' The WCF service has to be configured to specify the List return type. 
    ' To specify the List collection type, open the Configure Service Reference dialog and 
    ' select the System.Collections.Generic.List type from the Collection type list. 
    
    Console.WriteLine("See the existing departments and courses.")
    DisplayDepartmentsAndCourses()
    Console.WriteLine()
    Console.WriteLine()
    
    ' Use some IDs to create
    ' new Department and Course. 
    ' The newly created objects will
    ' be then deleted.
    
    Dim departmentID As Integer = 100
    
    Dim courseID As Integer = 50
    
    AddNewDepartmentAndCourses(departmentID, courseID)
    Console.WriteLine("See existing and added.")
    DisplayDepartmentsAndCourses()
    Console.WriteLine()
    UpdateDepartmentAndCourses(departmentID, courseID)
    Console.WriteLine("See existing and updated.")
    DisplayDepartmentsAndCourses()
    Console.WriteLine()
    DeleteDepartmentAndCourses(departmentID)
    
    // Note, the service's GetDepartments method returns System.Collections.Generic.List.
    // By default, when WCF generates a proxy the return collection types are converted to IEnumerable.
    // The WCF service has to be configured to specify the List return type. 
    // To specify the List collection type, open the Configure Service Reference dialog and 
    // select the System.Collections.Generic.List type from the Collection type list. 
    
    Console.WriteLine("See the existing departments and courses.");
    DisplayDepartmentsAndCourses();
    Console.WriteLine();
    Console.WriteLine();
    
    // Use some IDs to create
    // new Department and Course. 
    // The newly created objects will
    // be then deleted.
    
    int departmentID = 100;
    
    int courseID = 50;
    
    AddNewDepartmentAndCourses(departmentID, courseID);
    Console.WriteLine("See existing and added.");
    DisplayDepartmentsAndCourses();
    Console.WriteLine();
    UpdateDepartmentAndCourses(departmentID, courseID);
    Console.WriteLine("See existing and updated.");
    DisplayDepartmentsAndCourses();
    Console.WriteLine();
    DeleteDepartmentAndCourses(departmentID);
    
  8. クラスに次のメソッドを追加します。 このメソッドは、サービスから返されるオブジェクトの表示方法、新しいオブジェクトの追加方法、オブジェクトの更新方法、およびオブジェクトの削除方法を示します。 詳細については、コードのコメントを参照してください。

    Private Sub DisplayDepartmentsAndCourses()
        Using service = New Service1Client()
            ' Get all the departments.
            Dim departments As List(Of Department) = service.GetDepartments()
            For Each d In departments
                Console.WriteLine("ID: {0}, Name: {1}", d.DepartmentID, d.Name)
                ' Get all the courses for each department. 
                ' The reason we are able to access
                ' the related courses is because the service eagrly loaded the related objects 
                ' (using the System.Data.Objects.ObjectQuery(T).Include method).
                For Each c In d.Courses.OfType(Of OnlineCourse)()
                    Console.WriteLine(" OnLineCourse ID: {0}, Title: {1}", c.CourseID, c.Title)
                Next
                For Each c In d.Courses.OfType(Of OnsiteCourse)()
                    Console.WriteLine(" OnSiteCourse ID: {0}, Title: {1}", c.CourseID, c.Title)
                Next
            Next
        End Using
    End Sub
    
    
    Private Sub AddNewDepartmentAndCourses(ByVal departmentID As Integer, ByVal courseID As Integer)
        Using service = New Service1Client()
    
            Dim newDepartment As New Department() _
                With {.DepartmentID = departmentID, _
                      .Budget = 13000D, _
                      .Name = "New Department", _
                      .StartDate = DateTime.Now _
                     }
    
            Dim newCourse As New OnlineCourse() _
                With {.CourseID = courseID, _
                     .DepartmentID = departmentID, _
                     .URL = "http://www.fineartschool.net/Trigonometry", _
                     .Title = "New Onsite Course", _
                     .Credits = 4 _
                     }
    
            ' Add the course to the department.
            newDepartment.Courses.Add(newCourse)
    
            ' The newly create objects are marked as added, the service will insert these into the store. 
            service.UpdateDepartment(newDepartment)
    
            ' Let’s make few more changes to the saved object. 
            ' Since the previous changes have now been persisted, call AcceptChanges to
            ' reset the ChangeTracker on the objects and mark the state as ObjectState.Unchanged.
            ' Note, AcceptChanges sets the tracking on, so you do not need to call StartTracking
            ' explicitly.
            newDepartment.AcceptChanges()
            newCourse.AcceptChanges()
    
            ' Because the change tracking is enabled
            ' the following change will set newCourse.ChangeTracker.State to ObjectState.Modified.
            newCourse.Credits = 6
    
            service.UpdateDepartment(newDepartment)
        End Using
    End Sub
    
    Private Sub UpdateDepartmentAndCourses(ByVal departmentID As Integer, ByVal courseID As Integer)
        Using service = New Service1Client()
            ' Get all the departments.
            Dim departments As List(Of Department) = service.GetDepartments()
            ' Use LINQ to Objects to query the departments collection 
            ' for the specific department object.
            Dim department As Department = departments.Single(Function(d) d.DepartmentID = departmentID)
            department.Budget = department.Budget - 1000D
    
            ' Get the specified course that belongs to the department.
            ' The reason we are able to access the related course
            ' is because the service eagrly loaded the related objects 
            ' (using the System.Data.Objects.ObjectQuery(T).Include method).
            Dim existingCourse As Course = department.Courses.[Single](Function(c) c.CourseID = courseID)
            existingCourse.Credits = 3
    
            service.UpdateDepartment(department)
        End Using
    End Sub
    
    Private Sub DeleteDepartmentAndCourses(ByVal departmentID As Integer)
        Using service = New Service1Client()
            Dim departments As List(Of Department) = service.GetDepartments()
    
            Dim department As Department = departments.Single(Function(d) d.DepartmentID = departmentID)
    
            ' When MarkAsDeleted is called, the entity is removed from the collection,
            ' if we modify the collection over which foreach is looping an exception will be thrown.
            ' That is why we need to make a copy of the courses collection by 
            ' calling department.Courses.ToList();
            Dim courses As List(Of Course) = department.Courses.ToList()
            For Each c In courses
    
                ' Marks each comment for the post as Deleted.
                ' If another entity have a foreign key relationship with this Course object
                ' an exception will be thrown during save operation. 
                c.MarkAsDeleted()
            Next
    
            department.MarkAsDeleted()
            service.UpdateDepartment(department)
        End Using
    End Sub
    
    static void DisplayDepartmentsAndCourses()
    {
        using (var service = new Service1Client())
        {
            // Get all the departments.
            List<Department> departments = service.GetDepartments();
            foreach (var d in departments)
            {
                Console.WriteLine("ID: {0}, Name: {1}", d.DepartmentID, d.Name);
                // Get all the courses for each department. 
                // The reason we are able to access
                // the related courses is because the service eagrly loaded the related objects 
                // (using the System.Data.Objects.ObjectQuery(T).Include method).
                foreach (var c in d.Courses.OfType<OnlineCourse>())
                {
                    Console.WriteLine("  OnLineCourse ID: {0}, Title: {1}", c.CourseID, c.Title);
                }
                foreach (var c in d.Courses.OfType<OnsiteCourse>())
                {
                    Console.WriteLine("  OnSiteCourse ID: {0}, Title: {1}", c.CourseID, c.Title);
                }
            }
        }
    }
    
    
    static void AddNewDepartmentAndCourses(int departmentID, int courseID)
    {
        using (var service = new Service1Client())
        {
            Department newDepartment = new Department()
            {
                DepartmentID = departmentID,
                Budget = 13000.000m,
                Name = "New Department",
                StartDate = DateTime.Now
            };
    
            OnlineCourse newCourse = new OnlineCourse()
            { 
                CourseID = courseID,
                DepartmentID = departmentID,
                URL = "http://www.fineartschool.net/Trigonometry",
                Title = "New Onsite Course",
                Credits = 4
            };
    
            // Add the course to the department.
            newDepartment.Courses.Add(newCourse);
    
            // The newly create objects are marked as added, the service will insert these into the store. 
            service.UpdateDepartment(newDepartment);
    
            // Let’s make few more changes to the saved object. 
            // Since the previous changes have now been persisted, call AcceptChanges to
            // reset the ChangeTracker on the objects and mark the state as ObjectState.Unchanged.
            // Note, AcceptChanges sets the tracking on, so you do not need to call StartTracking
            // explicitly.
            newDepartment.AcceptChanges();
            newCourse.AcceptChanges();
    
            // Because the change tracking is enabled
            // the following change will set newCourse.ChangeTracker.State to ObjectState.Modified.
            newCourse.Credits = 6;
            service.UpdateDepartment(newDepartment);
    
        }
    }
    
    static void UpdateDepartmentAndCourses(int departmentID, int courseID)
    {
        using (var service = new Service1Client())
        {
            // Get all the departments.
            List<Department> departments = service.GetDepartments();
            // Use LINQ to Objects to query the departments collection 
            // for the specific department object.
            Department department = departments.Single(d => d.DepartmentID == departmentID);
            department.Budget = department.Budget - 1000.00m;
    
            // Get the specified course that belongs to the department.
            // The reason we are able to access the related course
            // is because the service eagrly loaded the related objects 
            // (using the System.Data.Objects.ObjectQuery(T).Include method).
            Course existingCourse = department.Courses.Single(c => c.CourseID == courseID);
            existingCourse.Credits = 3;
    
            service.UpdateDepartment(department);
        }
    }
    
    static void DeleteDepartmentAndCourses(int departmentID)
    {
        using (var service = new Service1Client())
        {
            List<Department> departments = service.GetDepartments();
    
            Department department = departments.Single(d => d.DepartmentID == departmentID);
    
            // When MarkAsDeleted is called, the entity is removed from the collection,
            // if we modify the collection over which foreach is looping an exception will be thrown.
            // That is why we need to make a copy of the courses collection by 
            // calling department.Courses.ToList();
            List<Course> courses = department.Courses.ToList();
            foreach (var c in courses)
            {
    
                // Marks each comment for the post as Deleted.
                // If another entity have a foreign key relationship with this Course object
                // an exception will be thrown during save operation. 
                c.MarkAsDeleted();
            }
    
            department.MarkAsDeleted();
            service.UpdateDepartment(department);
        }
    }
    

WPF クライアント アプリケーションを使用してサービスをテストするには

  1. WPF アプリケーションを作成します。 前のプロジェクトと同じソリューションで、プロジェクト名に「STESchoolModelWPFTest」と入力します。

  2. STEASchoolModelService サービスへの参照を追加します。 サービスへの参照を追加するには、ソリューション エクスプローラーで参照フォルダーを右クリックし、[サービス参照の追加] をクリックします。

    既定では、WCF によって、IEnumerable コレクションを返すプロキシが生成されます。 STESchoolModelServiceGetDepartments メソッドは List を返すため、適切な戻り値の型を指定するようにサービスを構成する必要があります。

  3. サービス名 (ServiceReference1) を右クリックし、[サービス参照の構成] をクリックします。 [サービス参照の構成] ダイアログ ボックスで、[コレクション型] ボックスの一覧から [System.Collections.Generic.List] 型を選択します。

  4. STESchoolModelTypes プロジェクトへの参照を追加します。

  5. app.config ファイルを開き、ファイルに接続文字列を追加します。 STESchoolModel プロジェクトの app.config ファイルを開き、connectionStrings 要素をコピーして、Web.config ファイルの configuration 要素の子要素として追加します。

    STESchoolModel プロジェクトの app.config ファイルは、もう使用されることがないため、今すぐ削除できます。

    既定では、プロジェクト テンプレートによって、MainWindow.xaml ファイルと対応する分離コード ファイルがプロジェクトに追加されます。

  6. MainWindow.xaml を開き、既定の XAML コードを、WPF の STESchoolModelWPFTest ウィンドウを定義する XAML に置き換えます。 詳細については、コードのコメントを参照してください。

    <Window x:Class="STESchoolModelWPFTest.MainWindow"
            xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="508" Width="919" Loaded="Window_Loaded">
        <!-- The code begind code sets the departmentsItemsGrid to the root of the object graph.-->
        <Grid Name="departmentsItemsGrid">
            <!-- comboBoxDepartment points to the root of the graph, that is why the Path is not specified-->
            <ComboBox DisplayMemberPath="DepartmentID" ItemsSource="{Binding}"
                      IsSynchronizedWithCurrentItem="true" 
                      Height="23" Margin="122,12,198,0" Name="comboBoxDepartment" VerticalAlignment="Top"/>
            <!-- listViewItems Path is set to Courses because it is bound to Department.Courses.-->
            <ListView ItemsSource="{Binding Path=Courses}" Name="listViewItems" Margin="34,46,34,50" >
                <ListView.View>
                    <GridView AllowsColumnReorder="False" ColumnHeaderToolTip="Courses" >
                        <GridViewColumn DisplayMemberBinding="{Binding Path=CourseID}" 
                            Header="CourseID" Width="70"/>
                        <!--The TextBox controls are embedded in the two of the following columns.
                            This is done to enable editing in the ListView control. -->
                        <GridViewColumn Header="Title" Width="100">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBox Height="25" Width="100" Text="{Binding Path=Title}" />
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Credits" Width="100" >
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBox Height="25" Width="100" Text="{Binding Path=Credits}" />
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                    </GridView>
                </ListView.View>
            </ListView>
            <Label Height="28" Margin="34,12,0,0" Name="departmentLabel" VerticalAlignment="Top" 
                   HorizontalAlignment="Left" Width="93">Department:</Label>
            <!--When the Save and Close button is clicked all the objects will be sent to the service 
                where all the updated objects will be saved to the database. -->
            <Button Height="23" HorizontalAlignment="Right" Margin="0,0,34,12" 
                    Name="buttonClose" VerticalAlignment="Bottom" Width="127" Click="buttonClose_Click">Save and Close</Button>
        </Grid>
    </Window>
    
  7. MainWindow.xaml.cs (または .vb) ファイルを開き、既定の分離コードを次のコードに置き換えます (詳細については、コードのコメントを参照してください)。

    Class MainWindow
        Dim departments As List(Of Department)
    
        Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
            Using service = New Service1Client()
                ' Set the parent of of your data bound controls to the root of the graph.
                ' In the xaml page the appropriate paths should be set on each data bound control.
                ' For the comboBoxDepartment it is empty because it is bound to Departments (which is root).
                ' For the listViewItems it is set to Courses because it is bound to Department.Courses.
                ' Note, that the TextBox controls are embedded in the two of the columns in the listViewItems.
                ' This is done to enable editing in the ListView control.
                departments = service.GetDepartments()
                Me.departmentsItemsGrid.DataContext = departments
            End Using
        End Sub
    
        Private Sub buttonSave_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles buttonSave.Click
            Using service = New Service1Client()
                ' Save all the departments and their courses. 
                For Each department In departments
                    service.UpdateDepartment(department)
    
                    ' Call AcceptChanges on all the objects 
                    ' to resets the change tracker and set the state of the objects to Unchanged.
                    department.AcceptChanges()
                    For Each course In department.Courses
                        course.AcceptChanges()
                    Next
                Next
            End Using
        End Sub
    
        Private Sub buttonClose_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles buttonClose.Click
            ' Close the form.
            Me.Close()
        End Sub
    End Class
    
    public partial class MainWindow : Window
    {
        private List<Department> departments;
    
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            using (var service = new Service1Client())
            {
                // Set the parent of of your data bound controls to the root of the graph.
                // In the xaml page the appropriate paths should be set on each data bound control.
                // For the comboBoxDepartment it is empty because it is bound to Departments (which is root).
                // For the listViewItems it is set to Courses because it is bound to Department.Courses.
                // Note, that the TextBox controls are embedded in the two of the columns in the listViewItems.
                // This is done to enable editing in the ListView control.
                departments = service.GetDepartments();
                this.departmentsItemsGrid.DataContext = departments;
            }
        }
    
        private void buttonSave_Click(object sender, RoutedEventArgs e)
        {
            using (var service = new Service1Client())
            {
                // Save all the departments and their courses. 
                foreach (var department in departments)
                {
                    service.UpdateDepartment(department);
    
                    // Call AcceptChanges on all the objects 
                    // to resets the change tracker and set the state of the objects to Unchanged.
                    department.AcceptChanges();
                    foreach (var course in department.Courses)
                        course.AcceptChanges();
                }
            }
    
        }
    
        private void buttonClose_Click(object sender, RoutedEventArgs e)
        {
            //Close the form.
            this.Close();
        }
    }
    

参照

概念

自己追跡エンティティの使用
オブジェクトのシリアル化 (Entity Framework)
N 層アプリケーションのビルド (Entity Framework)

その他のリソース

ADO.NET Self-Tracking Entity Template