¿Cómo garantizar que los proxies se creen cuando se utiliza el patrón de repository con el marco de entidades?

Tengo este método en mi clase SurveyController:

public ActionResult AddProperties(int id, int[] propertyids, int page = 1) { var survey = _uow.SurveyRepository.Find(id); if (propertyids == null) return GetPropertiesTable(survey, page); var repo = _uow.PropertySurveyRepository; propertyids.Select(propertyid => new PropertySurvey { //Setting the Property rather than the PropertyID //prevents the error occurring later //Property = _uow.PropertyRepository.Find(propertyid), PropertyID = propertyid, SurveyID = id }) .ForEach(x => repo.InsertOrUpdate(x)); _uow.Save(); return GetPropertiesTable(survey, page); } 

GetPropertiesTable vuelve a mostrar Propiedades pero PropertySurvey.Property se marca como virtual y he creado la entidad utilizando el nuevo operador, por lo que nunca se creó un proxy para admitir la carga diferida y es nulo cuando accedo a él. Cuando tenemos acceso directo a DbContext, podemos usar el método Create para crear explícitamente el proxy . Pero aquí tengo una unidad de trabajo y un patrón de repository. Supongo que podría exponer el contexto. Crear método a través de un repository. Crear método y luego tengo que recordar usarlo en lugar del nuevo operador cuando agregue una entidad. ¿Pero no sería mejor encapsular el problema en mi método InsertOrUpdate? ¿Hay alguna manera de detectar que la entidad que se está agregando no es un proxy cuando debería ser y sustituir un proxy? Este es mi método InsertOrUpdate en mi clase de repository base:

  protected virtual void InsertOrUpdate(T e, int id) { if (id == default(int)) { // New entity context.Set().Add(e); } else { // Existing entity context.Entry(e).State = EntityState.Modified; } } 

Basado en la respuesta proporcionada por qujck. Aquí es cómo puede hacerlo sin tener que emplear Automapper:

Editado para verificar siempre el proxy, no solo durante la inserción, como se sugiere en los comentarios

Editado nuevamente para usar una forma diferente de verificar si un proxy fue pasado al método. La razón para cambiar la técnica es que me topé con un problema cuando introduje una entidad que heredó de otra. En ese caso, una entidad heredada puede fallar a la entity.e.GetType().Equals(instance.GetType() incluso si es un proxy. Obtuve la nueva técnica de esta respuesta

 public virtual T InsertOrUpdate(T e) { DbSet dbSet = Context.Set(); DbEntityEntry entry; if (e.GetType().BaseType != null && e.GetType().Namespace == "System.Data.Entity.DynamicProxies") { //The entity being added is already a proxy type that supports lazy //loading - just get the context entry entry = Context.Entry(e); } else { //The entity being added has been created using the "new" operator. //Generate a proxy type to support lazy loading and attach it T instance = dbSet.Create(); instance.ID = e.ID; entry = Context.Entry(instance); dbSet.Attach(instance); //and set it's values to those of the entity entry.CurrentValues.SetValues(e); e = instance; } entry.State = e.ID == default(int) ? EntityState.Added : EntityState.Modified; return e; } public abstract class ModelBase { public int ID { get; set; } } 

Estoy de acuerdo con usted en que esto debe manejarse en un solo lugar y el mejor lugar para captar todos los aspectos para que sea su repository. Puede comparar el tipo de T con una instancia creada por el contexto y usar algo como Automapper para transferir rápidamente todos los valores si los tipos no coinciden.

 private bool mapCreated = false; protected virtual void InsertOrUpdate(T e, int id) { T instance = context.Set().Create(); if (e.GetType().Equals(instance.GetType())) instance = e; else { //this bit should really be managed somewhere else if (!mapCreated) { Mapper.CreateMap(e.GetType(), instance.GetType()); mapCreated = true; } instance = Mapper.Map(e, instance); } if (id == default(int)) context.Set().Add(instance); else context.Entry(instance).State = EntityState.Modified; }