Ninject MVC 2,EF 4,AutoMapper - ObjectContext的已被释放

问题描述:

全面修订

好吧,我使用Ninject与MVC 2扩展我的DI容器,AutoMapper我的实体LT; - >视图模型映射器。我发现了一个'ObjectContext的配置的错误在我的视图模型 - >实体映射。我的code如下。

Okay, I'm using Ninject with the MVC 2 extension as my DI container, and AutoMapper as my entity <--> view model mapper. I'm getting an 'ObjectContext is disposed' error in my view model -> entity mapping. My code is below.

Ninject绑定:

Ninject bindings:

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映射定义:

My controller's constructor, which includes my AutoMapper map definitions:

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

这是第二个映射在这里是非常重要的。

It's the second mapping that's important here.

接下来是我的编辑方式:

Next is my Edit method:

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

最后,堆栈跟踪:

Finally, the stack trace:

[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

继在调试过程中,我的ObjectContext公司(HGEntities)连接保持完好,直到我的视图模型 - >游戏地图被调用。由于某些原因,连接设置在该点。任何想法,为什么这是怎么回事?

Following the process in the debugger, my ObjectContext's (HGEntities) connection remains intact until my view model -> game map is invoked. For some reason, the connection is disposed at that point. Any ideas as to why that's happening?

根据在文档他们实际上阻止你使用的工厂。我使用他们,但有可能它现在可能解决您的问题。我在我自己的DI与ninject旅途点收到此错误,但很难说为什么你得到你的。对我来说,它是由关系和延迟加载造成的。启用延迟加载你的对象扶住到ObjectContext的一个参考,这样他们就可以填充相关的对象和相关对象的集合。

Based on the documentation they actually discourage you from using factories. I use them but it is possible it might now solve your problem. I was getting this error at a point in my own DI with ninject journey, but it is hard to say why you are getting yours. For me it was being caused by relationships and lazy loading. With lazy loading enabled your objects hold on to a reference to the ObjectContext, so they can populate related objects and collections of related objects.

底线,我想如果你张贴你的错误堆栈跟踪,所以我们可以帮助你确切地知道,当它发生时它会有所帮助。

Bottom line, I think it would help if you posted the stack trace for your error so we can help you know exactly when it is occurring.

希望这有助于。

编辑:我认为这个问题是你救的方法。如果你处理的对象上下文的,当你在游戏进行编辑。我不认为这会在ObjectStateManager看到你的行:

I think the issue is in your save method. If you dispose of your object context when you get the game to edit it. I don't think it will be in the ObjectStateManager see your line:

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

你从AutoMapper得到你目前的游戏对象不依附于任何ObjectContext的。下面是我使用的更新方法:

Your current game object that you got from the AutoMapper is not attached to any ObjectContext. Here is the method I use for updates:

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的对象上下文中的Dispose方法。

I didn't come up with it myself found it somewhere on the web. It's works well for me. I would adjust your save method to incorporate it. If you need assistance let me know. The other thing I would recommend (small) is to set your Object context to null in your dispose method.

好运!

编辑:好了,再试试......基础上,构造你的管理控制你有私有变量为您repositores

Okay, another try... based on the constructor for your admin controller do you have private variables for your repositores?

private IGameRepository _gameRepository;

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

正在ninject创建控制器?我没有看到AdminController在绑定列表中。我没有看到的 [注入] 您的任何构造的属性。你刚才忽略它,当你发布到堆栈或者他们不存在?

Are Controllers being created by ninject? I don't see AdminController in your list of bindings. I am not seeing the [Inject] attribute on any of your constructors. Did you just omit it when you posted to stack or are they not there?

我的其他想法是,如果你不与应用InSingletonScope内存问题(泄露)()为您的上下文可能是合适的答案。

My other thought is if you are not having any memory issues (leaks) with the application InSingletonScope() for your context might be the appropriate answer.

对不起,所有的问题,但我只是想了解这个问题越好。

Sorry for all the questions but I am just trying to understand the issue better.