Tutorial: Asignar la herencia - Tabla por jerarquía (Herramientas de Entity Data Model)

En este tema se muestra cómo implementar la herencia de tabla por jerarquía modificando el modelo conceptual definido en un archivo .edmx. La herencia de tabla por jerarquía usa una tabla de base de datos para mantener los datos de todos los tipos de entidad en una jerarquía de la herencia.

En este tutorial, implementará la herencia de tabla por jerarquía modificando el modelo conceptual que se usa en la aplicación CourseManager (para obtener más información, vea la sección Requisitos previos, más adelante en este tema).

En el modelo conceptual de CourseManager, el tipo de entidad Person tiene dos propiedades, HireDate y EnrollmentDate, que pueden pertenecer a los nuevos tipos de entidad (Instructor y Student, respectivamente) que heredan de Person. Los pasos siguientes resumen cómo implementar la herencia de tabla por jerarquía en este caso. Los procedimientos de este tutorial proporcionan más detalles.

  1. Cree dos tipos de entidad nuevos, Instructor y Student.

  2. Establezca el tipo base para cada nuevo tipo de entidad en Person.

  3. Mueva la propiedad HireDate de Person a Instructor y mueva la propiedad EnrollmentDate de Person a Student.

  4. Convierta el tipo de entidad Person en un tipo abstracto.

  5. Asigne el tipo de entidad Instructor a la tabla Person con dos condiciones: HireDate Is Not Null y EnrollmentDate Is Null.

  6. Asigne el tipo de entidad Student a la tabla Person con dos condiciones: EnrollmentDate Is Not Null e HireDate Is Null.

Requisitos previos

Para completar este tutorial, debe compilar la aplicación CourseManager. Para obtener más información e instrucciones, vea el Tutorial rápido de Entity Framework. Después de compilar esta aplicación, implementará la herencia de tabla por jerarquía modificando su modelo conceptual y sus asignaciones. A continuación, extenderá la funcionalidad de la aplicación para mostrar la inscripción de un curso seleccionado.

Cc716683.note(es-es,VS.100).gifNota:
Dado que muchos de los temas del tutorial de esta documentación usan la aplicación CourseManager como punto de partida, recomendamos que utilice una copia de la misma en este tutorial, en lugar de modificar el código original de CourseManager.

Este tutorial supone que el lector tiene conocimientos básicos de Visual Studio, .NET Framework y sobre la programación en Visual C# o Visual Basic.

Implementar la herencia de tabla por jerarquía

En este procedimiento, modificará SchoolModel para implementar la herencia de tabla por jerarquía. Para ver una presentación en vídeo del siguiente procedimiento, vea Cómo modelar la herencia de tabla por jerarquía con las herramientas de Entity Framework.

Para implementar la herencia de tabla por jerarquía

  1. Abra la solución CourseManager en Visual Studio.

  2. En el Explorador de soluciones, haga doble clic en el archivo School.edmx.

    El archivo School.edmx se abre en ADO.NET Entity Data Model Designer (Entity Designer).

  3. Haga clic con el botón secundario en un área vacía de la superficie de diseño de Entity Designer, seleccione Agregar y, a continuación, haga clic en Entity.

    Aparece el cuadro de diálogo Nueva entidad.

  4. Escriba Instructor como Nombre de entidad y seleccione Person en la lista desplegable para el Tipo base.

  5. Haga clic en Aceptar.

    Se crea y se muestra un nuevo tipo de entidad en la superficie de diseño.

  6. Repita los pasos 3 a 5, pero escriba Student como Nombre de entidad en el segundo paso.

    Ahora tiene dos tipos de entidad nuevos, Instructor y Student, que se muestran en la superficie de diseño. Las flechas señalan desde los nuevos tipos de entidad al tipo de entidad Person; esto indica que Person es el tipo base para los nuevos tipos de entidad.

  7. Haga clic con el botón secundario en la propiedad HireDate (debajo de Propiedades escalares) del tipo de entidad Person. Seleccione Cortar.

  8. Haga clic con el botón secundario en Propiedades escalares del tipo de entidad Instructor y seleccione Pegar.

  9. Haga clic con el botón secundario en la propiedad HireDate y seleccione Propiedades.

  10. En la ventana Propiedades, establezca la propiedad Nullable en false.

  11. Repita los pasos 7 a 10, pero corte la propiedad EnrollmentDate del tipo de entidad Person y péguelo en el tipo de entidad Student.

  12. Seleccione el tipo de entidad Person. En la ventana Propiedades, establezca su propiedad Abstract en true.

    No tiene que usar los tipos abstractos para modelar escenarios en los que se usa la tabla por jerarquía en general. Los tipos abstractos se usan en este ejemplo para mostrar su uso en un modelo conceptual.

    Cc716683.note(es-es,VS.100).gifNota:
    Los pasos restantes de este procedimiento requieren la ventana Detalles de la asignación.Si esta ventana no está visible, haga clic con el botón secundario en la superficie de diseño principal y seleccione Detalles de la asignación.

  13. Seleccione el tipo de entidad Instructor y haga clic en <Agregar una tabla o vista> en la ventana Detalles de la asignación.

    El campo <Agregar una tabla o vista> se convierte en una lista desplegable de tablas o vistas a las que se puede asignar la entidad seleccionada.

  14. En la lista desplegable, seleccione Person.

    La ventana Detalles de la asignación se actualiza con las asignaciones de columnas predeterminadas y una opción para agregar una condición.

  15. Haga clic en <Agregar condición>.

    El campo <Agregar una condición> se convierte en una lista desplegable de columnas para las que se pueden establecer condiciones.

  16. En la lista desplegable, seleccione HireDate.

    Aparece otro campo <Agregar una condición>.

  17. En la columna Operador de la ventana Detalles de la asignación, seleccione Es en la lista desplegable.

  18. En la columna Propiedad/Valor, seleccione No NULL.

  19. Haga clic en <Agregar condición>.

  20. En la lista desplegable, seleccione EnrollmentDate.

  21. En la columna Operador, seleccione Es en la lista desplegable.

  22. En la columna Propiedad/Valor, seleccione NULL.

    Cc716683.note(es-es,VS.100).gifNota:
    Si un valor o propiedad se utiliza en una condición que tampoco puede ser una propiedad de entidad, a menos que la condición utilice una comparación Is Null o Is Not Null.

  23. Repita los pasos 13 a 22 para el tipo de entidad Student, pero establezca las condiciones HireDate Is Null y EnrollmentDate Is Not Null.

Ahora se implementa la herencia de tabla por jerarquía.

Crear una asociación entre Instructor y OfficeAssignment

En esta sección cambiará la asociación entre Person y OfficeAssignment para que sea entre Instructor y OfficeAssignment. Si se cambia la asociación de esta forma, se es coherente con el propósito del modelo.

Para crear una asociación entre Instructor y OfficeAssignment

  1. Haga clic con el botón secundario en la asociación entre Person y OfficeAssignment, y seleccione Eliminar.

  2. Haga clic con el botón secundario en un área vacía de la superficie de diseño de Entity Designer, elija Agregar y, a continuación, seleccione Asociación.

  3. Para un Extremo de la asociación, seleccione Instructor en la lista desplegable Entidad y seleccione 1 (Una) en la lista desplegable Multiplicidad.

  4. Para el otro Extremo de la asociación, seleccione OfficeAssignment en la lista desplegable Entidad y seleccione 0..1 (Cero o una) en la lista desplegable Multiplicidad.

  5. Haga clic en Aceptar.

  6. Haga clic con el botón secundario en la nueva asociación entre Instructor y OfficeAssignment, y seleccione Propiedades.

  7. En la ventana Propiedades, haga clic en Restricción referencial y, a continuación, haga clic en el botón de puntos suspensivos (…) que aparece en la columna de valor.

    Aparece el cuadro de diálogo Restricción referencial.

  8. Seleccione Instructor en la lista desplegable Principal.

  9. Haga clic en Aceptar.

Ya ha agregado una asociación entre Instructor y OfficeAssignment.

Construir la interfaz de usuario

Después, agregará un botón al formulario CourseViewer que carga y muestra el formulario Enrollment. A continuación, agregará dos controles ComboBox y un control ListBox al formulario Enrollment. El primer ComboBox le permite seleccionar un departamento. El segundo ComboBox le permite seleccionar un curso basado en el departamento seleccionado en el primer ComboBox. Una lista de alumnos e instructores para el curso seleccionado se muestra en el control ListBox.

Para construir la interfaz de usuario

  1. Haga clic con el botón secundario en el proyecto CourseManager en el Explorador de soluciones, seleccione Agregar y seleccione Nuevo elemento.

    Aparecerá el cuadro de diálogo Agregar nuevo elemento.

  2. Seleccione Windows Forms, establezca el nombre del formulario en Enrollment.vb o Enrollment.cs (en función del lenguaje que use) y haga clic en Agregar.

    Se agrega un formulario nuevo al proyecto y se abre en el diseñador de formularios. El nombre del formulario se establece en Enrollment y el texto en Enrollment.

  3. Arrastre un control ComboBox del cuadro de herramientas al formulario y establezca su nombre en departmentList en la ventana Propiedades.

  4. Arrastre otro control ComboBox hacia el formulario y establezca su nombre en courseList.

  5. Arrastre un control Listbox del cuadro de herramientas al formulario. Establezca su nombre en studentList en la ventana Propiedades.

  6. En el Explorador de soluciones, haga doble clic en el formulario CourseViewer.cs o CourseViewer.vb.

    La vista de diseño del formulario CourseViewer aparece.

  7. Arrastre un control Button del cuadro de herramientas al formulario CourseViewer.

  8. En la ventana Propiedades, establezca el nombre del botón en viewEnrollment y establezca el texto del botón en View Enrollment.

  9. Haga doble clic en el botón viewEnrollment.

    El archivo de código subyacente para el formulario CourseViewer se abre.

  10. Agregue el código siguiente al controlador de eventos viewEnrollment_click:

    Dim enrollmentForm As New Enrollment()
    enrollmentForm.Visible = True
    
    Enrollment enrollmentForm = new Enrollment();
    enrollmentForm.Visible = true;
    

La interfaz de usuario está completa ahora.

Consultar el modelo conceptual

En este procedimiento, consultará el modelo conceptual y enlazará los resultados a los controles de Windows Forms. Para obtener más información sobre cómo enlazar objetos a controles, vea Binding Objects to Controls (Entity Framework).

Para consultar el modelo conceptual

  1. Con el formulario Enrollment abierto en el diseñador de formularios, haga doble clic en el formulario Enrollment.

    El archivo de código subyacente para el formulario Enrollment se abre.

  2. Agregue las instrucciones using (C#) o Imports (Visual Basic) siguientes.

    Imports System.Data.Objects
    Imports System.Data.Objects.DataClasses
    
    using System.Data.Objects;
    using System.Data.Objects.DataClasses;
    
  3. Agregue una propiedad a la clase Enrollment que representa el contexto de datos:

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities
    
    // Create an ObjectContext instance based on SchoolEntities.
    private SchoolEntities schoolContext;
    
  4. En el controlador de eventos Enrollment_Load, agregue el código para inicializar el contexto del objeto y enlazar el control ComboBox a una consulta que devuelve todos los departamentos y la información del curso relacionada.

          ' Initialize the ObjectContext.
          schoolContext = New SchoolEntities()
    
          ' Define a query that returns all Department objects and 
          ' related Course objects, ordered by name.
          Dim departmentQuery As ObjectQuery(Of Department) = _
              schoolContext.Departments.Include("Courses") _
              .OrderBy("it.Name")
    
          ' Bind the ComboBox control to the query, which is 
          ' executed during data binding.
          Me.departmentList.DataSource = departmentQuery _
    .Execute(MergeOption.OverwriteChanges)
          Me.departmentList.DisplayMember = "Name"
    
    // Initialize the ObjectContext.
    schoolContext = new SchoolEntities();
    
    // Define a query that returns all Department objects
    // and related Course objects, ordered by name.
    ObjectQuery<Department> departmentQuery =
        schoolContext.Departments.Include("Courses")
                                .OrderBy("it.Name");
    
    // Bind the ComboBox control to the query.
    this.departmentList.DataSource = departmentQuery
        .Execute(MergeOption.OverwriteChanges);
    this.departmentList.DisplayMember = "Name";
    
  5. Vuelva a la vista de diseño del formulario Enrollment y haga doble clic en el control departmentList ComboBox.

    El controlador de eventos departmentList_SelectedIndexChanged se crea en el código subyacente del archivo.

  6. Agregue el código al controlador de eventos para enlazar courseList el control ComboBox a las propiedades Course del Department seleccionado.

    ' Get the object for the selected department
    Dim department As Department = CType(Me.departmentList _
            .SelectedItem, Department)
    
    ' Bind the ComboBox control Course properties of
    ' the selected Department.
    courseList.DataSource = department.Courses
    courseList.DisplayMember = "Title"
    
    // Get the object for the selected department.
    Department department =
            (Department)this.departmentList.SelectedItem;
    
    // Bind the ComboBox control to the Course  
    // properties of the selected Department.
    courseList.DataSource = department.Courses;
    courseList.DisplayMember = "Title";
    
  7. Vuelva a la vista de diseño del formulario Enrollment y haga doble clic en el control courseList ComboBox.

    El controlador de eventos courseList_SelectedIndexChanged se crea en el código detrás del archivo.

  8. Agregue código al controlador de eventos para mostrar una lista de alumnos en ListBox.

    Me.studentList.Items.Clear()
    
    ' Get the CourseID from the selected Course.
    Dim course As Course = CType(Me.courseList.SelectedItem,  _
         Course)
    Dim courseId As Integer = course.CourseID
    
    ' Get all StudentGrade objects for the supplied CourseID
    Dim studentQuery As Course = schoolContext.Courses.Where _
         ("it.CourseID = @courseID", New ObjectParameter _
          ("courseID", courseId)).Include("StudentGrades"). _
          FirstOrDefault()
    
    ' Get all students for each StudentGrade
    For Each cg As StudentGrade In studentQuery.StudentGrades
        cg.PersonReference.Load()
        studentList.Items.Add(cg.Person.LastName + ", " + _
                            cg.Person.FirstName)
    Next
    
    studentList.Items.Add(" ")
    
    ' Get all Instructor types for the supplied CourseID
    Dim instructorQuery As Course = schoolContext.Courses. _
         Where("it.CourseID = @courseID", New ObjectParameter _
               ("courseID", courseId)).Include("People") _
               .FirstOrDefault()
    
    ' Display each instructor for the specified Course
    For Each Instructor As Instructor In instructorQuery.People
        Me.studentList.Items.Add("Instructor: " + Instructor. _
                        LastName + ", " + Instructor.FirstName)
    Next
    
    studentList.Items.Clear();
    
    // Get the CourseID from the selected Course.
    Course course = (Course)courseList.SelectedItem;
    int courseId = course.CourseID;
    
    // Get all StudentGrade types for the supplied CourseID
    Course studentQuery = schoolContext.Courses.Where(
        "it.CourseID = @courseID", new ObjectParameter
            ("courseID", courseId)).Include("StudentGrades").
            FirstOrDefault();
    
    // Get all students for each StudentGrade
    foreach (StudentGrade sg in studentQuery.StudentGrades)
    {
        sg.PersonReference.Load();
        studentList.Items.Add(sg.Person.LastName + ", " +
            sg.Person.FirstName);
    }
    
    studentList.Items.Add(" ");
    
    // Get all Instructor types for the supplied CourseID
    Course instructorQuery = schoolContext.Courses.Where(
        "it.CourseID = @courseID", new ObjectParameter
            ("courseID", courseId)).Include("People").
            FirstOrDefault();
    
    // Display each instructor for the specified course.
    foreach (Instructor instructor in instructorQuery.People.
        OfType<Instructor>())
    {
        studentList.Items.Add("Instructor: " + instructor.
            LastName + ", " + instructor.FirstName);
    }
    

La aplicación se ha completado ahora. Presione Ctrl+F5 para ejecutar la aplicación. Haga clic en el botón View Enrollment para cargar el formulario Enrollment. La inscripción del curso e instructores para el curso seleccionado se muestran en ListBox.

Códigos

Esta sección muestra la versión final del archivo de código subyacente para el formulario Enrollment.

Imports System.Data.Objects
Imports System.Data.Objects.DataClasses

Public Class Enrollment

    ' Create an ObjectContext instance based on SchoolEntity.
    Private schoolContext As SchoolEntities

    Private Sub Enrollment_Load(ByVal sender As System.Object, _
                ByVal e As System.EventArgs) Handles MyBase.Load
        ' Initialize the ObjectContext.
        schoolContext = New SchoolEntities()

        ' Define a query that returns all Department objects and 
        ' related Course objects, ordered by name.
        Dim departmentQuery As ObjectQuery(Of Department) = _
            schoolContext.Departments.Include("Courses") _
            .OrderBy("it.Name")

        ' Bind the ComboBox control to the query, which is 
        ' executed during data binding.
        Me.departmentList.DataSource = departmentQuery _
  .Execute(MergeOption.OverwriteChanges)
        Me.departmentList.DisplayMember = "Name"
    End Sub

    Private Sub departmentList_SelectedIndexChanged(ByVal sender _
            As System.Object, ByVal e As System.EventArgs) Handles _
            departmentList.SelectedIndexChanged
        ' Get the object for the selected department
        Dim department As Department = CType(Me.departmentList _
                .SelectedItem, Department)

        ' Bind the ComboBox control Course properties of
        ' the selected Department.
        courseList.DataSource = department.Courses
        courseList.DisplayMember = "Title"
    End Sub

    Private Sub courseList_SelectedIndexChanged(ByVal sender As  _
            System.Object, ByVal e As System.EventArgs) Handles _
            courseList.SelectedIndexChanged
        Me.studentList.Items.Clear()

        ' Get the CourseID from the selected Course.
        Dim course As Course = CType(Me.courseList.SelectedItem,  _
             Course)
        Dim courseId As Integer = course.CourseID

        ' Get all StudentGrade objects for the supplied CourseID
        Dim studentQuery As Course = schoolContext.Courses.Where _
             ("it.CourseID = @courseID", New ObjectParameter _
              ("courseID", courseId)).Include("StudentGrades"). _
              FirstOrDefault()

        ' Get all students for each StudentGrade
        For Each cg As StudentGrade In studentQuery.StudentGrades
            cg.PersonReference.Load()
            studentList.Items.Add(cg.Person.LastName + ", " + _
                                cg.Person.FirstName)
        Next

        studentList.Items.Add(" ")

        ' Get all Instructor types for the supplied CourseID
        Dim instructorQuery As Course = schoolContext.Courses. _
             Where("it.CourseID = @courseID", New ObjectParameter _
                   ("courseID", courseId)).Include("People") _
                   .FirstOrDefault()

        ' Display each instructor for the specified Course
        For Each Instructor As Instructor In instructorQuery.People
            Me.studentList.Items.Add("Instructor: " + Instructor. _
                            LastName + ", " + Instructor.FirstName)
        Next
    End Sub
End Class
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Objects;
using System.Data.Objects.DataClasses;

namespace CourseManager
{
    public partial class Enrollment : Form
    {
        // Create an ObjectContext instance based on SchoolEntities.
        private SchoolEntities schoolContext;

        public Enrollment()
        {
            InitializeComponent();
        }

        private void Enrollment_Load(object sender, EventArgs e)
        {
            // Initialize the ObjectContext.
            schoolContext = new SchoolEntities();

            // Define a query that returns all Department objects
            // and related Course objects, ordered by name.
            ObjectQuery<Department> departmentQuery =
                schoolContext.Departments.Include("Courses")
                                        .OrderBy("it.Name");

            // Bind the ComboBox control to the query.
            this.departmentList.DataSource = departmentQuery
                .Execute(MergeOption.OverwriteChanges);
            this.departmentList.DisplayMember = "Name";
        }

        private void departmentList_SelectedIndexChanged(object sender,
            EventArgs e)
        {
            // Get the object for the selected department.
            Department department =
                    (Department)this.departmentList.SelectedItem;

            // Bind the ComboBox control to the Course  
            // properties of the selected Department.
            courseList.DataSource = department.Courses;
            courseList.DisplayMember = "Title";
        }

        private void courseList_SelectedIndexChanged(object sender,
            EventArgs e)
        {
            studentList.Items.Clear();

            // Get the CourseID from the selected Course.
            Course course = (Course)courseList.SelectedItem;
            int courseId = course.CourseID;

            // Get all StudentGrade types for the supplied CourseID
            Course studentQuery = schoolContext.Courses.Where(
                "it.CourseID = @courseID", new ObjectParameter
                    ("courseID", courseId)).Include("StudentGrades").
                    FirstOrDefault();

            // Get all students for each StudentGrade
            foreach (StudentGrade sg in studentQuery.StudentGrades)
            {
                sg.PersonReference.Load();
                studentList.Items.Add(sg.Person.LastName + ", " +
                    sg.Person.FirstName);
            }

            studentList.Items.Add(" ");

            // Get all Instructor types for the supplied CourseID
            Course instructorQuery = schoolContext.Courses.Where(
                "it.CourseID = @courseID", new ObjectParameter
                    ("courseID", courseId)).Include("People").
                    FirstOrDefault();

            // Display each instructor for the specified course.
            foreach (Instructor instructor in instructorQuery.People.
                OfType<Instructor>())
            {
                studentList.Items.Add("Instructor: " + instructor.
                    LastName + ", " + instructor.FirstName);
            }
        }
    }
}

Pasos siguientes

Ha implementado correctamente la herencia de tabla por jerarquía en un modelo conceptual. Para obtener más información sobre cómo definir un modelo conceptual con herencia de tabla por jerarquía, vea How to: Define a Model with Table-per-Hierarchy Inheritance. Para obtener más información sobre cómo compilar aplicaciones con Entity Framework, vea ADO.NET Entity Framework.

Vea también

Otros recursos

Escenarios de las herramientas de Entity Data Model
Tareas de herramientas de Entity Data Model