0

UnitOfWorkManager

public class UnitOfWorkManager : IUnitOfWorkManager
{
    private bool _isDisposed;
    private readonly BEMContext _context;

    public UnitOfWorkManager(IBEMContext context)
    {
        // http://stackoverflow.com/questions/3552000/entity-framework-code-only-error-the-model-backing-the-context-has-changed-sinc
        Database.SetInitializer<BEMContext>(null);

        _context = context as BEMContext;
    }

    /// <summary>
    /// Provides an instance of a unit of work. This wrapping in the manager
    /// class helps keep concerns separated
    /// </summary>
    /// <returns></returns>
    public IUnitOfWork NewUnitOfWork()
    {
        return new UnitOfWork(_context);
    }

    /// <summary>
    /// Make sure there are no open sessions.
    /// In the web app this will be called when the injected UnitOfWork manager
    /// is disposed at the end of a request.
    /// </summary>
    public void Dispose()
    {
        if (!_isDisposed)
        {
            _context.Dispose();
            _isDisposed = true;
        }
    }
}

UnitOfWork

public class UnitOfWork : IUnitOfWork
{
    private readonly BEMContext _context;
    private readonly IDbTransaction _transaction;
    private readonly ObjectContext _objectContext;

    /// <summary>
    /// Constructor
    /// </summary>
    public UnitOfWork(BEMContext context)
    {
        _context = context;

        // In order to make calls that are overidden in the caching ef-wrapper, we need to use
        // transactions from the connection, rather than TransactionScope. 
        // This results in our call e.g. to commit() being intercepted 
        // by the wrapper so the cache can be adjusted.
        // This won't work with the dbcontext because it handles the connection itself, so we must use the underlying ObjectContext. 
        // http://blogs.msdn.com/b/diego/archive/2012/01/26/exception-from-dbcontext-api-entityconnection-can-only-be-constructed-with-a-closed-dbconnection.aspx
        _objectContext = ((IObjectContextAdapter)_context).ObjectContext;

        if (_objectContext.Connection.State != ConnectionState.Open)
        {
            _objectContext.Connection.Open();
            _transaction = _objectContext.Connection.BeginTransaction();
        }
    }

    public void SaveChanges()
    {
        _context.SaveChanges();
    }

    public void Commit()
    {
        _context.SaveChanges();
        _transaction.Commit();
    }

    public void Rollback()
    {
        _transaction.Rollback();

        // http://blog.oneunicorn.com/2011/04/03/rejecting-changes-to-entities-in-ef-4-1/

        foreach (var entry in _context.ChangeTracker.Entries())
        {
            switch (entry.State)
            {
                case EntityState.Modified:
                    entry.State = EntityState.Unchanged;
                    break;
                case EntityState.Added:
                    entry.State = EntityState.Detached;
                    break;
                case EntityState.Deleted:
                    // Note - problem with deleted entities:
                    // When an entity is deleted its relationships to other entities are severed. 
                    // This includes setting FKs to null for nullable FKs or marking the FKs as conceptually null (don’t ask!) 
                    // if the FK property is not nullable. You’ll need to reset the FK property values to 
                    // the values that they had previously in order to re-form the relationships. 
                    // This may include FK properties in other entities for relationships where the 
                    // deleted entity is the principal of the relationship–e.g. has the PK 
                    // rather than the FK. I know this is a pain–it would be great if it could be made easier in the future, but for now it is what it is.
                    entry.State = EntityState.Unchanged;
                    break;
            }
        }
    }

    public void Dispose()
    {
        if (_objectContext.Connection.State == ConnectionState.Open)
        {
            _objectContext.Connection.Close();
        }
    }
}

言語リポジトリ

public class LanguageRepository : ILanguageRepository
{
    private readonly BEMContext _context;

    public LanguageRepository(IBEMContext context)
    {
        _context = context as BEMContext;
    }

    public Language Insert(Language language)
    {
        _context.Language.Add(language);

        return language;
    }
}

ローカリゼーション サービス

public class LocalizationService : ILocalizationService
{
    private readonly ILanguageRepository _languageRepository;

    public LocalizationService(ILanguageRepository languageRepository)
    {
        _languageRepository = languageRepository;
    }

    public void CreateLanguage(Language language)
    {
        _languageRepository.Insert(language);
    }
}

BaseController

public class BaseController : Controller
{
    protected readonly IUnitOfWorkManager _unitOfWorkManager;

    public BaseController(IUnitOfWorkManager unitOfWorkManager)
    {
        _unitOfWorkManager = unitOfWorkManager;
    }

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);
    }
}

LocalizationController

public class LocalizationController : BaseController
{
    private readonly ILocalizationService _localizationService;

    public LocalizationController(ILocalizationService localizationService, IUnitOfWorkManager unitOfWorkManager)
        : base(unitOfWorkManager)
    {
        _localizationService = localizationService;
    }

    public ActionResult AddLanguage()
    {
        return View();
    }

    [HttpPost]
    public ActionResult AddLanguage(LanguageModel model)
    {
        try
        {
            if (ModelState.IsValid)
            {
                using (var UnitOfWork = _unitOfWorkManager.NewUnitOfWork())
                {
                    try
                    {
                        var language = Mapper.Map<LanguageModel, Language>(model);
                        _localizationService.CreateLanguage(language);
                        UnitOfWork.Commit();
                    }
                    catch (Exception ex)
                    {
                        UnitOfWork.Rollback();
                        throw new Exception(ex.Message);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }

        return View(model);
    }
}

DBに言語を追加できません。service クラスと unitOfWork クラスは異なるコンテキストを使用するためです。サービスはコンテキストを変更しますが、UnitOfWork は変更を別のコンテキストに保存します。私は次のことを意味します:

のコンテキスト_localizationService.CreateLanguage(language); ここに画像の説明を入力

のコンテキストUnitOfWork ここに画像の説明を入力

もちろん、変更はdbには影響しません(エンティティをdbに追加できません)。2 つの異なる DbContex があるためです。説明できるといいのですが、この質問の仕方がわかりません。どうすればこの問題を解決できますか。

編集

次のようにIOCにUnity.MVC4を使用します

public static class Bootstrapper
{
    public static IUnityContainer Initialise()
    {
        var container = BuildUnityContainer();

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));

        return container;
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        // e.g. container.RegisterType<ITestService, TestService>();    
        RegisterTypes(container);

        return container;
    }

    public static void RegisterTypes(IUnityContainer container)
    {
        container.RegisterType<IBEMContext, BEMContext>();

        container.RegisterType<ILocalizationService, LocalizationService>();

        container.RegisterType<ILanguageRepository, LanguageRepository>();
        container.RegisterType<ILocaleResourceKeyRepository, LocaleResourceKeyRepository>();
        container.RegisterType<ILocaleResourceValueRepository, LocaleResourceValueRepository>();

        container.RegisterType<IUnitOfWorkManager, UnitOfWorkManager>();
    }
}
4

2 に答える 2