2

полностью пересмотренную:Ninject MVC 2, EF 4, AutoMapper - ObjectContext были захоронены

Хорошо, я использую Ninject с расширением MVC 2, как мой DI контейнер, и AutoMapper как мой сущности < -> Вид модель. Я получаю ошибку «ObjectContext isposed» в модели my view model ->. Мой код ниже.

Ninject привязок:

public class DIModule : NinjectModule 
{ 
    public override void Load() 
    { 
     this.Bind<HGEntities>().ToSelf().InRequestScope(); 
     this.Bind<IArticleRepository>().To<HGArticleRepository>().InRequestScope(); 
     this.Bind<IGameRepository>().To<HGGameRepository>().InRequestScope(); 
     this.Bind<INewsRepository>().To<HGNewsRepository>().InRequestScope(); 
     this.Bind<ErrorController>().ToSelf().InRequestScope(); 
     this.Bind<HGController>().ToSelf().InRequestScope(); 
    } 
} 

Мой репозиторий:

public class HGGameRepository : IGameRepository, IDisposable 
{ 
    private HGEntities _context; 

    public HGGameRepository(HGEntities context) 
    { 
     this._context = context; 
    } 

    // methods 

    public void SaveGame(Game game) 
    { 
     if (game.GameID > 0) 
     { 
      _context.ObjectStateManager.ChangeObjectState(game, System.Data.EntityState.Modified); 
     } 
     else 
     { 
      _context.Games.AddObject(game); 
     } 

     _context.SaveChanges(); 
    } 

    public void Dispose() 
    { 
     if (this._context != null) 
     { 
      this._context.Dispose(); 
     } 
    } 
} 

конструктор моего контроллера, который включает в себя мои определения карты AutoMapper:

public AdminController(IArticleRepository articleRepository, IGameRepository gameRepository, INewsRepository newsRepository) 
    { 
     _articleRepository = articleRepository; 
     _gameRepository = gameRepository; 
     _newsRepository = newsRepository; 

     Mapper.CreateMap<Game, AdminGameViewModel>() 
      .BeforeMap((s, d) => 
      { 
       int platCount = s.Platforms.Count; 
       var plats = s.Platforms.ToArray(); 
       d.PlatformIDs = new int[platCount]; 

       for (int i = 0; i < platCount; ++i) 
       { 
        d.PlatformIDs[i] = plats[i].PlatformID; 
       } 
      }) 
      .ForMember(dest => dest.Pros, opt => opt.MapFrom(src => src.Pros.Split(new char[] {'|'}))) 
      .ForMember(dest => dest.Cons, opt => opt.MapFrom(src => src.Cons.Split(new char[] {'|'}))) 
      .ForMember(dest => dest.PlatformIDs, opt => opt.Ignore()); 

     Mapper.CreateMap<AdminGameViewModel, Game>() 
      .BeforeMap((s, d) => 
      { 
       if (d.Platforms != null && d.Platforms.Count > 0) 
       { 
        var oldPlats = d.Platforms.ToArray(); 

        foreach (var oldPlat in oldPlats) 
        { 
         d.Platforms.Remove(oldPlat); 
        } 
       } 

       foreach (var platId in s.PlatformIDs) 
       { 
        var plat = _gameRepository.GetPlatform(platId); 
        d.Platforms.Add(plat); 
       } 
      }) 
      .ForMember(dest => dest.Platforms, opt => opt.Ignore()) 
      .ForMember(dest => dest.BoxArtPath, opt => opt.Ignore()) 
      .ForMember(dest => dest.IndexImagePath, opt => opt.Ignore()) 
      .ForMember(dest => dest.Cons, opt => opt.MapFrom(src => string.Join("|", src.Cons))) 
      .ForMember(dest => dest.Pros, opt => opt.MapFrom(src => string.Join("|", src.Pros))) 
      .ForMember(dest => dest.LastModified, opt => opt.UseValue(DateTime.Now)); 
    } 

Это второе отображение, важно здесь.

Следующая мой Изменить метод:

[HttpPost] 
    public ActionResult EditGame([Bind(Prefix="GameData")]AdminGameViewModel formData) 
    { 
     Game game = _gameRepository.GetGame(formData.GameID); 

     if (ModelState.IsValid) 
     { 
      game = AutoMapper.Mapper.Map<AdminGameViewModel, Game>(formData, game); 

    // it dies here, so the rest of the method is immaterial 
    } 

Наконец, трассировки стека:

[ObjectDisposedException: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.] 
System.Data.Objects.ObjectContext.EnsureConnection() +87 
System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) +90 
System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() +96 
System.Linq.Enumerable.FirstOrDefault(IEnumerable`1 source) +182 
System.Data.Objects.ELinq.ObjectQueryProvider.<GetElementFunction>b__1(IEnumerable`1 sequence) +74 
System.Data.Objects.ELinq.ObjectQueryProvider.ExecuteSingle(IEnumerable`1 query, Expression queryRoot) +95 
System.Data.Objects.ELinq.ObjectQueryProvider.System.Linq.IQueryProvider.Execute(Expression expression) +163 
System.Linq.Queryable.FirstOrDefault(IQueryable`1 source, Expression`1 predicate) +300 
HandiGamer.Domain.Concrete.HGGameRepository.GetPlatform(Int32 id) in C:\Users\Kevin\documents\visual studio 2010\Projects\HandiGamer\HandiGamer.Domain\Concrete\HGGameRepository.cs:68 
HandiGamer.WebUI.Controllers.AdminController.<.ctor>b__a(AdminGameViewModel s, Game d) in C:\Users\Kevin\documents\visual studio 2010\Projects\HandiGamer\HandiGamer\Controllers\AdminController.cs:56 
AutoMapper.<>c__DisplayClass1b.<BeforeMap>b__1a(Object src, Object dest) +139 
AutoMapper.TypeMap.<get_BeforeMap>b__0(Object src, Object dest) +118 
AutoMapper.Mappers.PropertyMapMappingStrategy.Map(ResolutionContext context, IMappingEngineRunner mapper) +196 
AutoMapper.Mappers.TypeMapMapper.Map(ResolutionContext context, IMappingEngineRunner mapper) +256 
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) +459 

[AutoMapperMappingException: 

Mapping types: 
AdminGameViewModel -> Game 
HandiGamer.WebUI.ViewModels.AdminGameViewModel -> HandiGamer.Domain.Entities.Game 

Destination path: 
Game 

Source value: 
HandiGamer.WebUI.ViewModels.AdminGameViewModel] 
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) +537 
AutoMapper.MappingEngine.Map(Object source, Object destination, Type sourceType, Type destinationType, Action`1 opts) +179 
AutoMapper.MappingEngine.Map(TSource source, TDestination destination, Action`1 opts) +190 
AutoMapper.MappingEngine.Map(TSource source, TDestination destination) +146 
AutoMapper.Mapper.Map(TSource source, TDestination destination) +105 
HandiGamer.WebUI.Controllers.AdminController.EditGame(AdminGameViewModel formData) in C:\Users\Kevin\documents\visual studio 2010\Projects\HandiGamer\HandiGamer\Controllers\AdminController.cs:323 
lambda_method(Closure , ControllerBase , Object[]) +162 
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +51 
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +409 
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +52 
System.Web.Mvc.<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a() +127 
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation) +436 
System.Web.Mvc.<>c__DisplayClassf.<InvokeActionMethodWithFilters>b__c() +61 
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +305 
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +830 
System.Web.Mvc.Controller.ExecuteCore() +136 
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +111 
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +39 
System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__4() +65 
System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +44 
System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +42 
System.Web.Mvc.Async.WrappedAsyncResult`1.End() +141 
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +54 
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40 
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +52 
System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38 
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +690 
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +194 

После процесса в отладчике (HGEntities) подключение моего ObjectContext остается нетронутым, пока мой взгляд, модель - > вызывается игра. По какой-то причине соединение расположено в этой точке. Любые идеи относительно того, почему это происходит?

+1

попробуйте сделать свое сопоставление вручную, посмотрите, будет ли это работать – Omu

+1

Почему вы размещаете контекст в репозитории? Вы не должны этого делать. Пусть Ninject обрабатывает его. Почему вы определяете правила для контроллеров? Это необязательно. – LukLed

ответ

0

Основываясь на documentation, они фактически препятствуют вам использовать фабрики. Я использую их, но возможно, теперь он может решить вашу проблему. Я получал эту ошибку в точке моего собственного DI с ninject-путешествием, но трудно сказать, почему вы получаете свое. Для меня это вызвано отношениями и ленивой нагрузкой. При ленивой загрузке ваши объекты сохраняют ссылку на ObjectContext, поэтому они могут заполнять связанные объекты и коллекции связанных объектов.

В нижней строке, я думаю, что это поможет, если вы разместите трассировку стека для своей ошибки, чтобы мы могли помочь вам точно знать, когда это происходит.

Надеюсь, это поможет.

Редактировать: Я думаю, проблема в вашем методе сохранения. Если вы избавляетесь от контекста объекта, когда вы получаете игру, чтобы ее отредактировать. Я не думаю, что это будет в ObjectStateManager увидеть свою линию:

_context.ObjectStateManager.ChangeObjectState(game, System.Data.EntityState.Modified); 

Ваш текущий объект игры, который вы получили от AutoMapper не привязан к какой-либо ObjectContext. Вот метод я использую для обновлений:

public void Update(TEntity entity) 
{ 
    object originalItem; 

    EntityKey key = Context.CreateEntityKey(Context.GetEntitySet<TEntity>().Name, entity); 

    if (Context.TryGetObjectByKey(key, out originalItem)) 
    { 
     Context.ApplyCurrentValues(key.EntitySetName, entity); 
    } 
} 

Не забудьте позвонить Context.SaveChanges();

я не придумал его сам нашел его где-то в Интернете. Это хорошо для меня. Я бы скорректировал ваш метод сохранения, чтобы включить его. Если вам нужна помощь, дайте мне знать. Другая вещь, которую я рекомендовал бы (небольшой), - установить для вашего объекта контекст значение null в методе удаления.

удачи!

Редактировать: Хорошо, еще одна попытка ... на основе конструктора для вашего контроллера администратора у вас есть личные переменные для ваших репозиториев?

private IGameRepository _gameRepository; 

public AdminController(IArticleRepository articleRepository, IGameRepository gameRepository, INewsRepository newsRepository) 
    { 
     _articleRepository = articleRepository; 
     _gameRepository = gameRepository; 
     _newsRepository = newsRepository; 

Являются ли контроллеры создаваемыми ninject? Я не вижу AdminController в вашем списке привязок. Я не вижу атрибута [Inject] для любого из ваших конструкторов. Вы просто опустили его, когда вы отправили в стек или они не были там?

Моя другая мысль, если у вас нет проблем с памятью (утечки) с приложением InSingletonScope() для вашего контекста, может быть подходящий ответ.

Извините за все вопросы, но я просто пытаюсь понять проблему лучше.

+0

Я отправлю трассировку стека позже, когда у меня будет доступ к моей машине dev. Когда я тестирую, вводя ObjectContext, используя InSingletonScope(), исправляет его, позволяя мне обновлять объекты без каких-либо исключений. Меня беспокоит только кеширование/потоки. Я не совсем уверен, как работает потоковая обработка, когда я исхожу из фона PHP. –

+0

Это имело бы смысл. (InSingletonScope()) просто добавьте комментарий после публикации вашего редактирования. – bytebender

+0

Добавлена ​​трассировка стека –

0

Мой собственный статический преобразователь работает отлично:

public static class GameMapper 
{ 
    public static Game MapFromEditModelToGame(IGameRepository repo, AdminGameViewModel formData, Game newGame) 
    { 
     newGame.GameID = formData.GameID; 
     newGame.GameTitle = formData.GameTitle; 
     newGame.GenreID = formData.GenreID; 
     newGame.LastModified = DateTime.Now; 
     newGame.ReviewScore = (short)formData.ReviewScore; 
     newGame.ReviewText = formData.ReviewText; 
     newGame.Cons = String.Join("|", formData.Cons); 
     newGame.Pros = String.Join("|", formData.Pros); 
     newGame.Slug = formData.Slug; 

     if (newGame.Platforms != null && newGame.Platforms.Count > 0) 
     { 
      var oldPlats = newGame.Platforms.ToArray(); 

      foreach (var oldPlat in oldPlats) 
      { 
       newGame.Platforms.Remove(oldPlat); 
      } 
     } 

     foreach (var platId in formData.PlatformIDs) 
     { 
      var plat = repo.GetPlatform(platId); 
      newGame.Platforms.Add(plat); 
     } 

     return newGame; 
    } 
} 

Вызванный как:

game = GameMapper.MapFromEditModelToGame(_gameRepository, formData, game); 

Сравните выше с моей AutoMapper карте определения:

Mapper.CreateMap<AdminGameViewModel, Game>() 
.BeforeMap((s, d) => 
{ 
    if (d.Platforms != null && d.Platforms.Count > 0) 
    { 
     var oldPlats = d.Platforms.ToArray(); 

     foreach (var oldPlat in oldPlats) 
     { 
      d.Platforms.Remove(oldPlat); 
     } 
    } 

    foreach (var platId in s.PlatformIDs) 
    { 
     var plat = _gameRepository.GetPlatform(platId); 
     d.Platforms.Add(plat); 
    } 
}) 
.ForMember(dest => dest.Platforms, opt => opt.Ignore()) 
.ForMember(dest => dest.BoxArtPath, opt => opt.Ignore()) 
.ForMember(dest => dest.IndexImagePath, opt => opt.Ignore()) 
.ForMember(dest => dest.Cons, opt => opt.MapFrom(src => string.Join("|", src.Cons))) 
.ForMember(dest => dest.Pros, opt => opt.MapFrom(src => string.Join("|", src.Pros))) 
.ForMember(dest => dest.LastModified, opt => opt.UseValue(DateTime.Now)); 

Единственная реальная разница мне переходя в репо в качестве аргумента.

Все остальные коды - мой контроллер, мой материал DI и т. Д. - это точно так же. только разница в том, что я использую свой собственный неуклюжий картограф. Не идеальная ситуация, но что-то.

1

Я вижу, что IDisposable не выполняется правильно. Maybee, что может стать причиной исключения из вашего распоряжения?

Смежные вопросы