2

完全に改訂:

さて、私はDIコンテナとしてMVC 2拡張機能を備えたNinjectを使用し、エンティティ<->ビューモデルマッパーとしてAutoMapperを使用しています。ビューモデル->エンティティマッピングで「ObjectContextisdisposed」エラーが発生します。私のコードは以下の通りです。

バインディングを挿入します:

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

ここで重要なのは2番目のマッピングです。

次は私の編集方法です:

    [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

デバッガーでのプロセスに続いて、ビューモデル->ゲームマップが呼び出されるまで、ObjectContext(HGEntities)の接続はそのまま残ります。何らかの理由で、接続はその時点で破棄されます。なぜそれが起こっているのかについてのアイデアはありますか?

4

3 に答える 3

1

IDisposableが正しく実装されていないようです。メイビーは、関連する例外を破棄する理由になる可能性がありますか?

于 2012-07-20T21:37:10.773 に答える
0

ドキュメントに基づいて、彼らは実際にあなたが工場を使うことを思いとどまらせます。私はそれらを使用しますが、それがあなたの問題を解決する可能性があります。私自身のDIのある時点で、このエラーが発生していましたが、なぜあなたがあなたのエラーを取得しているのかはわかりません。私にとって、それは関係と遅延読み込みによって引き起こされていました。遅延読み込みを有効にすると、オブジェクトは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();

私はそれを自分で思いついたわけではなく、ウェブ上のどこかで見つけました。それは私にとってはうまくいきます。保存方法を調整して組み込みます。サポートが必要な場合はお知らせください。私がお勧めするもう1つのこと(小さい)は、disposeメソッドでObjectコンテキストをnullに設定することです。

幸運を!

編集:さて、もう一度試してください...管理者コントローラーのコンストラクターに基づいて、リポジトリーのプライベート変数がありますか?

private IGameRepository _gameRepository;

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

コントローラーはninjectによって作成されていますか?バインディングのリストにAdminControllerが表示されません。[Inject]どのコンストラクターにも属性が表示されません。スタックに投稿するときに省略しましたか、それともそこにありませんか?

私の他の考えは、アプリケーションInSingletonScope()でメモリの問題(リーク)が発生していない場合は、適切な答えになる可能性があるということです。

すべての質問で申し訳ありませんが、私は問題をよりよく理解しようとしています。

于 2012-05-11T15:53:26.687 に答える
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など)はまったく同じです。唯一の違いは、私が自分の不器用なマッパーを使用していることです。理想的な状況ではありませんが、何か。

于 2012-05-15T01:21:42.500 に答える