我正在使用存储库和工作单元模式以及依赖项注入来通过Web应用程序中的实体框架5访问数据库。我有一个User
类,Entity Framework从该类生成代码优先数据库。
public class User
{
public Guid UserId { get; set; }
public string UserName { get; set; }
.
.
.
public string LanguagePreference { get; set; }
public virtual List<Role> Roles { get; set; }
public virtual List<Branch> Branches { get; set; }
}
我有一个用于添加或更新用户的
UserService
类。此类在构造函数中将IUserUnitOfWork
作为参数,并且Unity注入UserUnitOfwork
。 IUserUserOfWork
包含IRepository<User>
,IRepository<Location>
和IRepository<Role>
。这些由DI引导程序设置为Repository<T>
。 IUserUnitOfWork使用相同的实体框架DbContext设置不同的存储库。我这样做是因为我在更新与用户(位置和角色)相关的多对多关系时遇到问题。UserUnitOfWork:
public IRepository<Branch> BranchRepository {get; set;}
public IRepository<Role> RoleRepository { get; set; }
public IRepository<User> UserRepository { get; set; }
public DbContext Context { get; set; }
public UserUnitOfWork(DbContext context, ITransientErrorDetectionStrategy errorDetectionStrategy,RetryStrategy retryStrategy )
{
Context = context;
BranchRepository = new Repository<Branch>(context, errorDetectionStrategy, retryStrategy);
RoleRepository = new Repository<Role>(context, errorDetectionStrategy, retryStrategy);
UserRepository = new Repository<User>(context, errorDetectionStrategy, retryStrategy);
}
然后,存储库类使用Entity Framework 5访问数据库。
Repository.FirstOrDefault中的方法示例:
public virtual T FirstOrDefault(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "")
{
T result = null;
_retryPolicy.ExecuteAction(() =>
{
IQueryable<T> entities = GetHelper(filter, orderBy, includeProperties);
result = entities.FirstOrDefault();
});
return result;
}
并从存储库更新:
public virtual void Update(T entity)
{
if (_dbContext.Entry(entity).State == System.Data.EntityState.Detached)
{
_dbContext.Set<T>().Attach(entity);
_dbContext.Entry(entity).State = System.Data.EntityState.Modified;
}
}
所以我现在的问题是,当我更新用户时,它可以正确更新数据库中的数据,而当我注销并登录时,初始更改有效。但是,如果我再次更新并注销,即使数据库已更新,也不会选择新的更改。
我开始担心我采用的方法不正确,有人可以告诉我如何确保在执行更新时Entity Framework始终获得最新版本吗?
编辑:
所以我创建了一个Per Request Lifetime Manager,如下所示:
public class PerHttpRequestLifetimeManager : LifetimeManager
{
private readonly object key = new object();
public override object GetValue()
{
if (HttpContext.Current != null &&
HttpContext.Current.Items.Contains(key))
return HttpContext.Current.Items[key];
else
return null;
}
public override void RemoveValue()
{
if (HttpContext.Current != null)
HttpContext.Current.Items.Remove(key);
}
public override void SetValue(object newValue)
{
if (HttpContext.Current != null)
HttpContext.Current.Items[key] = newValue;
}
}
在我的DI启动程序中,我现在如下设置我的域上下文:
container.RegisterType<DbContext, DomainContext>(new PerHttpRequestLifetimeManager());
它似乎仍然无法正常工作,是我遗漏了其他东西还是设置不正确?
编辑2:
只是指出架构:
我们有一个MVC应用程序,它使用Angular JS对Web Api服务层进行Ajax调用。 Web Api中已注入ISomethingService。正是这个ISomethingService注入了存储库。由于同时运行MVC和Web API项目,PerHttpRequestLifetimeManager是否会引起混淆?
编辑3:
我如何保存已编辑用户的示例:
我们有一个
UserModel
类,用于在ServiceLayer-> API-> UI层与背面之间进行通信。 User
类是由实体框架代码首先生成的类。 UserService中的EditUser方法采用UserModel
。然后,我使用_unitOfWork.UserRepository来获取相应的数据库用户
var editedUser = _unitOfWork.UserRepository.FirstOrDefault(x => x.UserId == userModel.UserId);
我将字段从userModel映射到editedUser,然后调用(在UserService中)
_unitOfWork.UserRepository.Update(editedUser)
之后
_unitOfWork.Save()
还需要编辑:
因此,我编辑了一种更新用户表上的单个文本字段的简单方法(语言首选项)。我在更新后显式调用了dispose方法,以确保要处理该方法。
public void SetUserLanguagePreference(Guid userId, string language)
{
var user = _unitOfWork.UserRepository.FirstOrDefault(x => x.UserId == userId);
user.LanguagePreference = language;
_unitOfWork.UserRepository.Update(user);
_unitOfWork.Save();
_unitOfWork.Dispose();
}
UnitOfWork.Dispose()
调用存储库和Dbcontext的dispose方法数据库正确更新。但是,该行为仍然不正确。当我注销并首次登录时,它将检索正确的值。当我再次更改它并注销并再次登录时,它不会更新。这是以前的模式,它在我注销并登录后获得第一次更新,但是如果我再次更改并注销却无法进行选择。
最佳答案
最后,不是编辑而是答案!我们使用基于Claims的身份验证,并拥有一个覆盖ClaimsPrinciple Authenticate
方法的类,该方法在用户通过身份验证时都会被调用。
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal.Identity.IsAuthenticated)
{
//Check here if the authenticated user has access to this system
//using the user repository and if so add more claims to the token
}
return base.Authenticate(resourceName, incomingPrincipal);
}
无法使用DI注入此方法,因为它总是进入空的构造函数(不确定原因,但事实就是这样)。
因此,我们改为在空的构造函数中设置存储库,如下所示:
public PRAuthenticationManager()
{
_userRepository = DiBootstrapper.Container.Resolve<IRepository<User>>();
}
调用Authenticate方法时,我们将检查数据库中是否有声明附加到ClaimsPrincipal的用户。如果我们进行匹配,则会向令牌添加新的声明,然后将其用于以后每次对Web Api的调用。该存储库没有被处置(即使其他所有资源都已被处置),因此,当用户注销并从他们上次登录时就没有处置过的同一上下文中获得数据时,该存储库也就没有被处置。
整整三天试图找到那个...
关于c# - 使用存储库模式时, Entity Framework 不刷新数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22614773/