Saltar al contenido
¿Cómo crear relaciones entre entidades?

¿Cómo crear relaciones entre entidades?

El enfoque Code First de Entity Framework nos permite crear un modelo como una clase simple y, a continuación, la base de datos se crea a partir del modelo de dominio o la clase de entidad. En el enfoque Code First, la base de datos se crea a partir de las clases.

11min read

Algunas ventajas del enfoque de Entity Framework Code First incluyen (como se indica en el blog de Scott Gu):

  • Desarrollar sin tener que abrir un diseñador o definir un archivo de mapeo XML
  • Definir los objetos del modelo simplemente escribiendo "clases antiguas simples" sin necesidad de clases base
  • Usar un enfoque de "convención sobre configuración" que permite la persistencia de la base de datos sin configurar nada explícitamente
  • Opcionalmente, se invalida la persistencia basada en convenciones y se usa una API de código fluido para personalizar completamente la asignación de persistencia

Más bien profundizando más en conceptos teóricos, en esta publicación saltaremos directamente al código y crearemos una tabla y una base de datos utilizando el enfoque Code First. En este post aprenderemos cómo podemos crear entidades y una relación entre entidades en el enfoque de Entity Framework Code First. En el enfoque de EF Code First, hay dos opciones para crear la relación entre entidades, a través de:

  1. Anotaciones de datos
  2. Fluent API

En este post utilizaremos anotaciones de datos para crear la relación entre entidades.

Crear base de datos con una tabla

Comencemos con la creación de una tabla llamada Student en una base de datos con el enfoque de código primero. La clase de dominio Student se puede crear como se muestra en el siguiente listado:

namespace CodeFirstDemoApp
{
  public class Student
  {
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
  }

}

Como ya habrás notado, la clase Student es una clase simple. Entity Framework usará la clase Student para crear la tabla en la base de datos. La clase Student representa la entidad de dominio y no debe tener ninguna información o referencias de la base de datos. Entity Framework usará la clase Student para crear la tabla Student.

Una vez que se crea la clase de entidad de dominio, lo siguiente que debemos hacer es crear una clase Context que heredará la clase DataContext. La clase de contexto se puede crear como se muestra en la siguiente lista:

using System.Data.Entity;
namespace CodeFirstDemoApp
{
    public class Context : DbContext
    {
        public Context() : base()
        {

        }
        public DbSet<Student> Students { get; set; }
    }
}

Hemos creado la clase Context con el constructor predeterminado. Más adelante en el post hablaremos de varias opciones en el constructor. En la clase de contexto estamos realizando las siguientes tareas:

  • Creación del constructor predeterminado. Dado que no estamos pasando ningún parámetro en el constructor, EF creará una base de datos con el nombre como Namespace.Class name. Por lo tanto, en este caso, el nombre de la base de datos creada será CodeFirstDemo.Context.
  • Dado que no estamos pasando información de una cadena de conexión en el constructor de la clase Context, EF creará una base de datos en el servidor de base de datos predeterminado de SQL Server Express.
  • Para crear una base de datos en el servidor deseado con el nombre deseado, necesitamos crear la cadena de conexión y pasarla como parámetro en el constructor Context.
  • Para crear la tabla en la base de datos, cree una propiedad pública del tipo genérico DbSet con la entidad de dominio pasada en ella.

Hasta ahora hemos creado la clase de entidad Student y la clase Context. Ahora podemos escribir una consulta simple de LINQ to Entity para crear la base de datos y realizar las operaciones como se muestra en la lista a continuación:

using System;
using System.Linq;

namespace CodeFirstDemoApp
{
    class Program
    {
        static void Main(string[] args)
        {
            CreateStudent();
            Console.WriteLine("Student Created");

            using (Context c = new Context())
            {
                var result = from r in c.Students select r;
                
                foreach (var r in result)
                {
                    Console.WriteLine(r.Name);
                }
            }

            Console.ReadKey(true);
        }

        static void CreateStudent()
        {
            Student s = new Student
            {
                Id = 1,
                Age = 12,
                Name = "Foo"
            };

            using (Context c = new Context())
            {
                c.Students.Add(s);
                c.SaveChanges();
            }
        }
    }
}

Custom Database Name

Cuando trabajamos con el constructor predeterminado para la clase Context, EF crea de forma predeterminada la base de datos con un nombre completo como Namespace.Contextclass name. Sin embargo, podemos pasar el nombre deseado de la base de datos mydb en este caso en el constructor como se muestra en la lista a continuación:

public Context()
    : base("mydb")
{}

En SQL Express, EF creará una base de datos con el nombre mydb.

Trabajar con una cadena de conexión

A partir de ahora, confiamos en el EF para crear la base de datos. Sin embargo, podemos pasar una cadena de conexión para crear una base de datos en el servidor deseado y un nombre. La cadena de conexión se puede crear en el archivo de configuración como se indica a continuación:

<connectionStrings>
   <add name="democonnectionstring" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=Demo1;Integrated Security=True;MultipleActiveResultSets=true" providerName="System.Data.SqlClient" /></connectionStrings>

Hemos creado una cadena de conexión para crear una base de datos en el servidor de base de datos local. A continuación, debemos pasar el nombre de la cadena de conexión en el constructor de la clase Context como se muestra en la lista a continuación:

public Context() : base("name=democonnectionstring") {}

Relationship Between Entities

En el enfoque Code First, podemos crear una relación entre entidades utilizando cualquiera de las dos opciones:

  1. Anotaciones de datos
  2. Fluent API

En esta publicación crearemos una relación utilizando anotaciones de datos.

Relación uno a uno

Es posible que tengamos el requisito de crear relaciones uno a uno entre dos entidades. En otras palabras, necesitamos una relación de clave primaria – clave foránea entre dos entidades. Digamos que tenemos dos entidades y las siguientes reglas:

  1. Hay dos entidades denominadas Student y StudentAccount
  2. El estudiante es una entidad principal
  3. StudentAccount es una entidad dependiente de Student
  4. La clave principal de StudentAccount será la clave externa del estudiante

No deberíamos poder crear una StudentAccount sin un Student y solo puede haber una entrada de Student en StudentAccount. En pocas palabras, cada estudiante tendrá una cuenta de estudiante y no existirá ninguna cuenta de estudiante sin un estudiante.

Primero vamos a crear la entidad principal: Estudiante

 public class Student
 {
    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public virtual StudentAccount StudentAccount { get; set; }
 }

Como habrás notado, en la entidad Student tenemos una propiedad virtual del tipo StudentAccount que se crea como se muestra en el listado a continuación:

public class StudentAccount {
    public int Id {
        get;
        set;
    }

    public string Name {
        get;
        set;
    }

    public int Amount {
        get;
        set;
    }

    [Required] 
    public virtual Student Student {
        get;
        set;
    }
}

De nuevo, es posible que haya observado que en la entidad StudentAccount tenemos una propiedad virtual del tipo Student. Dado que Student es una entidad principal, la propiedad virtual Student de la entidad StudentAccount se anota como Required. Además, se puede crear una clase Context como se muestra en la siguiente lista:

using System.Data.Entity;
namespace CodeFirstDemoApp {
    public class Context : DbContext {
        public Context() : base("name=democonnectionstring") {}
        public DbSet<Student>Students {
            get;
            set;
        }

        public DbSet<StudentAccount>StudentAccounts {
            get;
            set;
        }
    }
}

Recuerde siempre que no podemos crear una fila en la tabla StudentAccounts a menos que no tengamos una fila correspondiente en la tabla Student.  Los datos se pueden crear en la tabla relacionada como se muestra en el listado a continuación:

static void CreateStudent() {

    Student s=new Student {
        Id=1,
        Age=12,
        Name="Foo"
    };

    StudentAccount sa=new StudentAccount {
        Amount=300,
        Name="Sports Account",
        Student=s
    };

    Context c=new Context();
    c.Students.Add(s);
    c.StudentAccounts.Add(sa);
    c.SaveChanges();

}

Como habrás notado, estamos estableciendo el objeto de Student como una propiedad de StudentAccount.  Podemos recuperar registros de ambas tablas como se muestra en el listado a continuación:

Context c=new Context();
var result=from r in c.Students select r;

foreach (var r in result) {
    Console.WriteLine(r.Name);
    Console.WriteLine(r.StudentAccounts.Amount);
}

Para verificar la relación entre entidades en SQL Server Management Studio, podemos ver las columnas creadas con las restricciones y claves como se muestra en la siguiente imagen:

Podemos ver las columnas creadas con las restricciones y claves como se muestra en la imagen

Aquí, la columna Id de la tabla StudentAccounts es tanto la clave principal como la clave externa.

Relación uno a muchos

Es posible que tengamos el requisito de crear una relación de más entre dos entidades. Digamos que tenemos dos entidades

  1. Hay dos entidades: Student y StudentAddress
  2. El estudiante es una entidad principal
  3. StudentAddress es una entidad dependiente de Student
  4. Un estudiante puede inscribirse en varias direcciones de estudiante

Un Student puede tener muchos StudentAddress. Una de las columnas de StudentAddress tendrá una clave externa como clave principal de Student.

Primero vamos a crear la entidad principal Estudiante,

public class Student {

    public Student() {
        StudentAddresses=new HashSet<StudentAddress>();
    }

    public int Id {
        get;
        set;
    }

    public string Name {
        get;
        set;
    }

    public int Age {
        get;
        set;
    }

    public ICollection<StudentAddress>StudentAddresses {
        get;
        set;
    }
}

Es posible que haya observado que estamos creando una propiedad de colección de StudentAddress y, a continuación, creando un valor establecido de la propiedad StudentAddress en el constructor de Student. La clase StudentAddress se puede crear como se muestra en la lista a continuación:

public class StudentAddress {

    public int Id {
        get;
        set;
    }

    public string Address {
        get;
        set;
    }

    public int StudentId {
        get;
        set;
    }

    public virtual Student Student {
        get;
        set;
    }
}

De nuevo, es posible que haya observado que en la entidad StudentAddress tenemos una propiedad virtual del tipo Student. Dado que Student es una entidad principal, la propiedad Student virtual de StudentAddress tiene una propiedad StudentId correspondiente.

Además, la clase Context se puede crear como se muestra en la lista a continuación:

public class Context : DbContext {

    public Context() : base("name=democonnectionstring") {}

    public DbSet<Student>Students {
        get;
        set;
    }

    public DbSet<StudentAddress>StudentAddresses {
        get;
        set;
    }
}

Recuerde siempre que no podemos crear una fila en la tabla StudentAddress a menos que no tengamos una fila correspondiente en la tabla Student. Los datos se pueden crear en la tabla relacionada como se muestra en el listado a continuación:

static void CreateStudent() {

    Student s=new Student {
        Id=1,
        Age=12,
        Name="Foo"
    };

    StudentAddress sa1=new StudentAddress {
        Address="Delhi",
        Id=1
    };

    StudentAddress sa2=new StudentAddress {
        Address="Bangalore",
        Id=2
    };

    s.StudentAddresses.Add(sa1);
    s.StudentAddresses.Add(sa2);

    Context c=new Context();
    c.Students.Add(s);
    c.SaveChanges();

}

Como habrás notado, estamos agregando los objetos de StudentAddress al Student.  Podemos recuperar registros de ambas tablas como se muestra en el siguiente listado:

static void Main(string[] args) {

    CreateStudent();
    Console.WriteLine("Student Created");


    Context c=new Context();
    var result=from r in c.Students.Include("StudentAddresses") select r;

    foreach (var r in result) {
        Console.WriteLine(r.Name);
        foreach(var a in r.StudentAddresses) {
            Console.WriteLine(a.Address);
        }
    }
    Console.ReadKey(true);
}

Para verificar la relación entre entidades en SQL Server Management Studio, podemos ver las columnas creadas con las restricciones y claves como se muestra en la siguiente imagen:

comprobar la relación entre entidades en SQL Server Management Studio

Many to Many Relationship

Por último, pero no menos importante, veamos cómo podemos configurar una relación de muchos a muchos. Supongamos que tenemos una entidad Student y una entidad Subject. Un estudiante puede estar matriculado en muchas asignaturas y una asignatura puede tener muchos estudiantes. Para crear una relación de demasiadas entre estas entidades, primero vamos a crear la entidad Student como se muestra en la lista a continuación:

public class Student {

    public Student() {
        Subjects=new HashSet<Subject>();
    }

    public int Id {
        get;
        set;
    }

    public string Name {
        get;
        set;
    }

    public int Age {
        get;
        set;
    }

    public ICollection<Subject>Subjects {
        get;
        set;
    }
}

Aquí estamos creando una propiedad de colección de Subjects y luego creando un valor establecido de la propiedad Subjects en el constructor de Student. La clase Subject se puede crear como se muestra en la lista a continuación:

public class Subject {

    public Subject() {
        Students=new HashSet<Student>();
    }

    public int Id {
        get;
        set;
    }

    public string Name {
        get;
        set;
    }

    public virtual ICollection<Student>Students {
        get;
        set;
    }
}

En la clase Subject también estamos creando la propiedad de la colección de Estudiantes y en el constructor de la clase Subject creando un conjunto de estudiantes. Esto es todo lo que tenemos que hacer para crear demasiadas relaciones entre entidades.

Además, la clase Context se puede crear como se muestra en la lista a continuación:

public class Context : DbContext {

    public Context() : base("name=democonnectionstring") {}

    public DbSet<Student>Students {
        get;
        set;
    }

    public DbSet<Subject>Subjects {
        get;
        set;
    }

}

Podemos crear las filas en la tabla Estudiantes y Asignaturas como se muestra en la lista a continuación:

static void CreateStudent() {

    Student s=new Student {
        Id=1,
        Age=12,
        Name="Foo"
    };

    Subject s1=new Subject {
        Id=1,
        Name="Phy"
    };

    Subject s2=new Subject {
        Id=2,
        Name="Maths"
    };

    s.Subjects.Add(s1);
    s.Subjects.Add(s2);

    Context c=new Context();
    c.Students.Add(s);
    c.SaveChanges();

}

Podemos recuperar registros de ambas tablas como se muestra aquí:

static void Main(string[] args) {

    CreateStudent();
    Console.WriteLine("Student Created");



    Context c=new Context();
    var result=from r in c.Students.Include("Subjects") select r;

    foreach (var r in result) {
        Console.WriteLine(r.Name);
        foreach(var a in r.Subjects) {
            Console.WriteLine(a.Name);
        }
    }
    Console.ReadKey(true);
}

Cuando verificamos la relación entre la entidad Estudiante y Sujeto, encontraremos que EF ha creado una tabla adicional para mantener la relación de muchos a muchos

verificar la relación entre la entidad Estudiante y la Asignatura

Así que ahí lo tienes, así es como se crean relaciones entre entidades en el enfoque Code First. En esta publicación, comenzamos trabajando con entidades individuales y luego procedimos a crear una relación entre las entidades. Espero que este post te sea útil, gracias por leer.

 

Infragistics Ultimate 15.2 ya está aquí.¡Descárgaloy mira su poder en acción!

Solicitar una demostración