Carga de entidades relacionadasLoading Related Entities

Entity Framework admite tres maneras de cargar datos relacionados: carga diligente, carga diferida y carga explícita.Entity Framework supports three ways to load related data - eager loading, lazy loading and explicit loading. Las técnicas que se muestran en este tema se aplican igualmente a los modelos creados con Code First y EF Designer.The techniques shown in this topic apply equally to models created with Code First and the EF Designer.

Cargando diligentementeEagerly Loading

La carga diligente es el proceso por el cual una consulta para un tipo de entidad también carga las entidades relacionadas como parte de la consulta.Eager loading is the process whereby a query for one type of entity also loads related entities as part of the query. La carga diligente se logra mediante el uso del método include.Eager loading is achieved by use of the Include method. Por ejemplo, las consultas siguientes cargarán blogs y todas las entradas relacionadas con cada blog.For example, the queries below will load blogs and all the posts related to each blog.

using (var context = new BloggingContext())
{
    // Load all blogs and related posts.
    var blogs1 = context.Blogs
                        .Include(b => b.Posts)
                        .ToList();

    // Load one blog and its related posts.
    var blog1 = context.Blogs
                       .Where(b => b.Name == "ADO.NET Blog")
                       .Include(b => b.Posts)
                       .FirstOrDefault();

    // Load all blogs and related posts
    // using a string to specify the relationship.
    var blogs2 = context.Blogs
                        .Include("Posts")
                        .ToList();

    // Load one blog and its related posts
    // using a string to specify the relationship.
    var blog2 = context.Blogs
                       .Where(b => b.Name == "ADO.NET Blog")
                       .Include("Posts")
                       .FirstOrDefault();
}

Nota

Include es un método de extensión en el espacio de nombres System. Data. Entity, por lo que debe asegurarse de que está usando ese espacio de nombres.Include is an extension method in the System.Data.Entity namespace so make sure you are using that namespace.

Carga de varios niveles diligentementeEagerly loading multiple levels

También es posible cargar diligentemente varios niveles de entidades relacionadas.It is also possible to eagerly load multiple levels of related entities. En las consultas siguientes se muestran ejemplos de cómo hacerlo para las propiedades de navegación de colección y de referencia.The queries below show examples of how to do this for both collection and reference navigation properties.

using (var context = new BloggingContext())
{
    // Load all blogs, all related posts, and all related comments.
    var blogs1 = context.Blogs
                        .Include(b => b.Posts.Select(p => p.Comments))
                        .ToList();

    // Load all users, their related profiles, and related avatar.
    var users1 = context.Users
                        .Include(u => u.Profile.Avatar)
                        .ToList();

    // Load all blogs, all related posts, and all related comments  
    // using a string to specify the relationships.
    var blogs2 = context.Blogs
                        .Include("Posts.Comments")
                        .ToList();

    // Load all users, their related profiles, and related avatar  
    // using a string to specify the relationships.
    var users2 = context.Users
                        .Include("Profile.Avatar")
                        .ToList();
}

Nota

Actualmente no es posible filtrar las entidades relacionadas que se cargan.It is not currently possible to filter which related entities are loaded. Incluir siempre incluirá todas las entidades relacionadas.Include will always bring in all related entities.

Carga diferidaLazy Loading

La carga diferida es el proceso por el que una entidad o colección de entidades se carga automáticamente desde la base de datos la primera vez que se tiene acceso a una propiedad que hace referencia a la entidad o entidades.Lazy loading is the process whereby an entity or collection of entities is automatically loaded from the database the first time that a property referring to the entity/entities is accessed. Al usar tipos de entidad POCO, la carga diferida se consigue creando instancias de tipos de proxy derivados y, a continuación, reemplazando las propiedades virtuales para agregar el enlace de carga.When using POCO entity types, lazy loading is achieved by creating instances of derived proxy types and then overriding virtual properties to add the loading hook. Por ejemplo, al usar la clase de entidad de blog que se define a continuación, se cargarán las publicaciones relacionadas la primera vez que se tenga acceso a la propiedad de navegación posts:For example, when using the Blog entity class defined below, the related Posts will be loaded the first time the Posts navigation property is accessed:

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
    public string Tags { get; set; }

    public virtual ICollection<Post> Posts { get; set; }
}

Desactivación de la carga diferida para la serializaciónTurn lazy loading off for serialization

La carga diferida y la serialización no se combinan bien y, si no tiene cuidado, puede finalizar la consulta de toda la base de datos, solo porque está habilitada la carga diferida.Lazy loading and serialization don’t mix well, and if you aren’t careful you can end up querying for your entire database just because lazy loading is enabled. La mayoría de los serializadores funcionan mediante el acceso a cada propiedad en una instancia de un tipo.Most serializers work by accessing each property on an instance of a type. El acceso de propiedad desencadena la carga diferida, por lo que se serializan más entidades.Property access triggers lazy loading, so more entities get serialized. En esas entidades se tiene acceso a las propiedades de, e incluso se cargan más entidades.On those entities properties are accessed, and even more entities are loaded. Se recomienda desactivar la carga diferida antes de serializar una entidad.It’s a good practice to turn lazy loading off before you serialize an entity. Se muestra cómo hacerlo en las secciones siguientes.The following sections show how to do this.

Desactivar la carga diferida para propiedades de navegación específicasTurning off lazy loading for specific navigation properties

La carga diferida de la colección de publicaciones se puede desactivar haciendo que la propiedad postes no sea virtual:Lazy loading of the Posts collection can be turned off by making the Posts property non-virtual:

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
    public string Tags { get; set; }

    public ICollection<Post> Posts { get; set; }
}

La carga de la colección de publicaciones se puede seguir usando la carga diligente (consulte la carga rápida anterior) o el método Load (vea carga explícita a continuación).Loading of the Posts collection can still be achieved using eager loading (see Eagerly Loading above) or the Load method (see Explicitly Loading below).

Desactivar la carga diferida para todas las entidadesTurn off lazy loading for all entities

La carga diferida se puede desactivar para todas las entidades en el contexto estableciendo una marca en la propiedad de configuración.Lazy loading can be turned off for all entities in the context by setting a flag on the Configuration property. Por ejemplo:For example:

public class BloggingContext : DbContext
{
    public BloggingContext()
    {
        this.Configuration.LazyLoadingEnabled = false;
    }
}

La carga de entidades relacionadas todavía se puede lograr mediante la carga diligente (consulte la carga rápida anterior) o el método Load (vea carga explícita a continuación).Loading of related entities can still be achieved using eager loading (see Eagerly Loading above) or the Load method (see Explicitly Loading below).

Cargar explícitamenteExplicitly Loading

Incluso con la carga diferida deshabilitada, todavía es posible cargar de forma diferida las entidades relacionadas, pero debe realizarse con una llamada explícita.Even with lazy loading disabled it is still possible to lazily load related entities, but it must be done with an explicit call. Para ello, use el método Load en la entrada de la entidad relacionada.To do so you use the Load method on the related entity’s entry. Por ejemplo:For example:

using (var context = new BloggingContext())
{
    var post = context.Posts.Find(2);

    // Load the blog related to a given post.
    context.Entry(post).Reference(p => p.Blog).Load();

    // Load the blog related to a given post using a string.
    context.Entry(post).Reference("Blog").Load();

    var blog = context.Blogs.Find(1);

    // Load the posts related to a given blog.
    context.Entry(blog).Collection(p => p.Posts).Load();

    // Load the posts related to a given blog
    // using a string to specify the relationship.
    context.Entry(blog).Collection("Posts").Load();
}

Nota

El método de referencia debe usarse cuando una entidad tiene una propiedad de navegación a otra entidad única.The Reference method should be used when an entity has a navigation property to another single entity. Por otro lado, el método de colección debe usarse cuando una entidad tiene una propiedad de navegación a una colección de otras entidades.On the other hand, the Collection method should be used when an entity has a navigation property to a collection of other entities.

El método de consulta proporciona acceso a la consulta subyacente que utilizará Entity Framework al cargar las entidades relacionadas.The Query method provides access to the underlying query that Entity Framework will use when loading related entities. Después, puede usar LINQ para aplicar filtros a la consulta antes de ejecutarlo con una llamada a un método de extensión LINQ como ToList, Load, etc. El método de consulta se puede utilizar con propiedades de navegación de referencia y de colección, pero es muy útil para las colecciones en las que se puede usar para cargar solo parte de la colección.You can then use LINQ to apply filters to the query before executing it with a call to a LINQ extension method such as ToList, Load, etc. The Query method can be used with both reference and collection navigation properties but is most useful for collections where it can be used to load only part of the collection. Por ejemplo:For example:

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Find(1);

    // Load the posts with the 'entity-framework' tag related to a given blog.
    context.Entry(blog)
           .Collection(b => b.Posts)
           .Query()
           .Where(p => p.Tags.Contains("entity-framework"))
           .Load();

    // Load the posts with the 'entity-framework' tag related to a given blog
    // using a string to specify the relationship.
    context.Entry(blog)
           .Collection("Posts")
           .Query()
           .Where(p => p.Tags.Contains("entity-framework"))
           .Load();
}

Cuando se usa el método de consulta, suele ser mejor desactivar la carga diferida para la propiedad de navegación.When using the Query method it is usually best to turn off lazy loading for the navigation property. Esto se debe a que, de lo contrario, es posible que el mecanismo de carga diferida cargue automáticamente toda la colección antes o después de que se haya ejecutado la consulta filtrada.This is because otherwise the entire collection may get loaded automatically by the lazy loading mechanism either before or after the filtered query has been executed.

Nota

Aunque la relación se puede especificar como una cadena en lugar de una expresión lambda, el IQueryable devuelto no es genérico cuando se usa una cadena y, por lo tanto, el método Cast suele ser necesario antes de que se pueda hacer nada útil con él.While the relationship can be specified as a string instead of a lambda expression, the returned IQueryable is not generic when a string is used and so the Cast method is usually needed before anything useful can be done with it.

A veces resulta útil saber el número de entidades relacionadas con otra entidad de la base de datos sin incurrir realmente en el costo de cargar todas esas entidades.Sometimes it is useful to know how many entities are related to another entity in the database without actually incurring the cost of loading all those entities. Se puede utilizar el método de consulta con el método Count de LINQ para hacerlo.The Query method with the LINQ Count method can be used to do this. Por ejemplo:For example:

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Find(1);

    // Count how many posts the blog has.
    var postCount = context.Entry(blog)
                           .Collection(b => b.Posts)
                           .Query()
                           .Count();
}