Come garantire che i proxy vengano creati quando si utilizza il modello di repository con il framework di entity framework?

Ho questo metodo nella mia class 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 visualizza nuovamente Properties ma PropertySurvey.Property è contrassegnato come virtual e ho creato l’ quadro utilizzando il nuovo operatore, quindi un proxy per supportare il caricamento lazy non è mai stato creato ed è nullo quando accedo ad esso. Quando abbiamo accesso diretto a DbContext, possiamo usare il metodo Create per creare esplicitamente il proxy . Ma ho qui un’unità di modello di lavoro e di deposito. Immagino di poter esporre il contesto.Creare il metodo tramite un repository.Create il metodo e quindi ho bisogno di ricordarmi di usarlo al posto del nuovo operatore quando aggiungo un’entity framework. Ma non sarebbe meglio incapsulare il problema nel mio metodo InsertOrUpdate? C’è un modo per rilevare che l’ quadro aggiunta non è un proxy quando dovrebbe essere e sostituire un proxy? Questo è il mio metodo InsertOrUpdate nella mia class di repository di 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; } } 

Basato sulla risposta fornita da qujck. Ecco come puoi farlo senza dover utilizzare l’automapper:

Modificato per controllare sempre il proxy, non solo durante l’inserimento, come suggerito nei commenti

Modificato di nuovo per utilizzare un modo diverso di verificare se un proxy è stato passato al metodo. La ragione per cambiare la tecnica è che mi sono imbattuto in un problema quando ho introdotto un’ quadro ereditata da un’altra. In tal caso un’ quadro ereditata può fallire l’ entity.e.GetType().Equals(instance.GetType() controlla anche se è un proxy. Ho ricevuto la nuova tecnica da questa risposta

 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; } } 

Sono d’accordo con te che questo dovrebbe essere gestito in un posto e il posto migliore per catturare tutti gli sguardi per essere il tuo repository. Puoi confrontare il tipo di T con un’istanza creata dal contesto e utilizzare qualcosa come Automapper per trasferire rapidamente tutti i valori se i tipi non corrispondono.

 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; }