visual tutorial studio mvc framework first existing español code c# entity-framework entity-framework-6

c# - tutorial - Obtener propiedades de navegación de entidades después de insertar



entity framework visual studio 2017 (4)

Tengo las siguientes 2 clases:

public class Reward { public int Id { get; set; } public int CampaignId { get; set; public virtual Campaign Campaign { get; set; } } public class Campaign { public int Id { get; set; } public virtual ICollection<Reward> Rewards { get; set; } }

Con esto tengo todas las cosas necesarias obvias como un DbContext y mappings.

Ahora digamos que creo una entidad de recompensa y la inserto así:

var reward = new Reward { CampaignId = 1 }; context.Set<Reward>().Add(reward); context.SaveChanges(); reward = context.Set<Reward>().SingleOrDefault(a => a.Id == reward.Id); //reward.Campaign is null

Obviamente tengo una campaña con Id 1, por lo que la restricción FK es feliz. Después de este inserto, mi entidad de recompensa tiene su nuevo conjunto de Id de identidad. Ahora el problema es que la recompensa sigue siendo solo la entidad de recompensa que creé. Y con esto, la recompensa. La propiedad de Campaña es nula. Parece que EF mantiene las entidades insertadas en la memoria, y cuando hago un .SingleOrDefault (a => a.Id == reward.Id) simplemente devuelve la entidad en la memoria, y no un nuevo proxy. Probablemente esto es algo bueno.

Entonces, la pregunta es: ¿cómo accede uno o carga las propiedades de navegación después de una inserción u obtiene un nuevo proxy que también tenga las propiedades de navegación como proxies?

¿Acaso estoy insertando en el camino equivocado?


¿Intentó usar Include() ? Algo como esto:

reward = context.Set<Reward>().Include("Campaigns").SingleOrDefault(a => a.Id == reward.Id);


A medida que crea su objeto de reward como new Reward() , EF no tiene un proxy. En su lugar, créelo usando DbSet.Cree así:

var reward = context.Set<Reward>().Create(); reward.CampaignId = 5; context.SaveChanges();

A continuación, adjúntelo a su DbSet:

context.Rewards.Attach(reward);

Finalmente, ahora puede usar la carga diferida para obtener entidades relacionadas:

var campaign = reward.Campaign;


Si lo entiendo correctamente, está intentando cargar ansiosamente una propiedad compleja después de establecer una relación a través de una propiedad de clave externa.

SaveChanges() no hace nada en la forma de cargar propiedades complejas. Como máximo, establecerá la propiedad de la clave principal si agrega nuevos objetos.

Su reward = context.Set<Reward>().SingleOrDefault(a => a.Id == reward.Id); línea reward = context.Set<Reward>().SingleOrDefault(a => a.Id == reward.Id); tampoco hace nada en la forma de cargar Campaign porque su objeto de recompensa no está adjunto al contexto. Necesitas decirle explícitamente a EF que cargue ese objeto complejo o que lo adjunte y que la carga lenta funcione.

Entonces, después de context.SaveChanges(); tienes tres opciones para cargar la reward.Campaign :

  1. Attach() recompensa al contexto para que Campaign se pueda cargar de forma perezosa (se carga cuando se accede)

    context.Rewards.Attach(reward);

    Nota: Solo podrá cargar reward.Campaign carga reward.Campaign en el alcance del contexto para que, si no va a acceder a ninguna propiedad dentro de la duración del contexto, use la opción 2 o 3.

  2. Load() manualmente Load() la propiedad Campaign

    context.Entry(reward).Reference(c => c.Campaign).Load();

  3. Include() manualmente Include() la propiedad Campaign

    reward = context.Rewards.Include("Campaigns") .SingleOrDefault(r => r.Id == reward.Id);

    Aunque, sugeriría Load ya que tienes una reward en memoria.

Consulte la sección Cargando objetos relacionados en este documento msdn para obtener más información.


Tengo una Solución simple alrededor del problema.

en lugar de agregar el CampaignID a la recompensa, agregue el objeto de la campaña ... entonces:

var _campaign = context.Campaign.First(c=>c.Id == 1);//how ever you get the ''1'' var reward = new Reward { Campaign = _campaign }; context.Set<Reward>().Add(reward); context.SaveChanges(); //reward.Campaign is not null

El marco de la entidad hace todo el trabajo pesado aquí.

Probablemente estés pensando que es un desperdicio cargar todo el objeto de Campaign, pero si vas a usarlo (por lo que parece, parece que lo estás), entonces no veo por qué no. Incluso puede usar la instrucción include al recuperarla arriba si necesita acceder a las propiedades de navegación desde el objeto Campaign ...

var _campaign = context.Campaign.include(/*what ever you may require*/).First(c=>c.Id = 1);