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