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

工作单位

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

基本控制器

public class BaseController : Controller
{
    protected readonly IUnitOfWorkManager _unitOfWorkManager;

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

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

本地化控制器

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

我无法向数据库添加语言。因为 service 和 unitOfWork 类使用不同的上下文。服务更改上下文,但 UnitOfWork 将更改保存在另一个上下文中。我的意思是以下:

上下文_localizationService.CreateLanguage(language); 在此处输入图像描述

上下文UnitOfWork 在此处输入图像描述

当然,更改不会影响 db(我无法将实体添加到 db)。因为有两个不同的 DbContex。我希望,我可以解释,但我不知道我该如何问这个问题。我怎么解决这个问题。

编辑

我将 Unity.MVC4 用于 IOC,如下所示

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

1

Unity 正在创建依赖项的新实例,这意味着在实例化 IUnitOfWorkManager 和 ILocalizationService 时,它​​们的依赖项将分别实例化。找到一种方法来共享对上下文的依赖;理想情况下,只有工作单元应该真正意识到它,其他任何事情都应该通过工作单元来改变上下文,我认为。

于 2013-09-05T13:03:08.030 回答
0

我的解决方案是:

/// <summary>
/// Bind the given interface in request scope
/// </summary>
public static class IOCExtensions
{
    public static void BindInRequestScope<T1, T2>(this IUnityContainer container) where T2 : T1
    {
        container.RegisterType<T1, T2>(new HierarchicalLifetimeManager());
    }

    public static void BindInSingletonScope<T1, T2>(this IUnityContainer container) where T2 : T1
    {
        container.RegisterType<T1, T2>(new ContainerControlledLifetimeManager());
    }
}

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.BindInRequestScope<IBEMContext, BEMContext>();

        container.BindInRequestScope<ILocalizationService, LocalizationService>();

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

        container.BindInRequestScope<IUnitOfWorkManager, UnitOfWorkManager>();
    }
}
于 2013-09-05T13:50:52.450 回答