我有使用 EF 4.3 和迁移的 ASP.NET MVC 4 应用程序。我使用 WebGrid Helper 为系统用户显示详细信息:
@grid.GetHtml(
headerStyle: "gridHeader",
footerStyle: "gridFooter",
firstText: "<< First",
previousText: "< Previous",
nextText: "Next >",
lastText: "Last >>",
alternatingRowStyle: "gridAlternativeRow",
columns: new[] {
grid.Column("Login", header: "User Login", canSort: true),
grid.Column("FullName", header: "User Name", canSort: true),
grid.Column("Email", header: "User Email", canSort: true),
grid.Column("Category", header: "User Category", canSort: true),
grid.Column(
"",
header: "",
format: @<text>
@Html.ActionLink("Edit", "Edit", new { id=item.Id} )
</text>
)
})
如您所见,Edit 操作方法负责编辑用户详细信息。这是它将视图模型传递给视图的方式:
public ActionResult Edit(int Id)
{
User user = repo.GetUser(Id);
RegisterModel rm = new RegisterModel();
rm.Id = user.Id;
rm.Name = user.FullName;
rm.UserName = user.Login;
rm.Email = user.Email;
rm.UserCategory = user.Category;
rm.Categories = new List<SelectListItem>();
List<Category> categories = repo.GetAllCategories();
foreach (var item in categories)
{
SelectListItem sli = new SelectListItem();
sli.Value = null;
sli.Text = item.Title;
if (user.Category == item.Title) sli.Selected = true;
rm.Categories.Add(sli);
}
return View(rm);
}
这就是它保存细节的方式:
[HttpPost]
public ActionResult Edit(RegisterModel rm, string NewPassword, string OldLogin)
{
if (NewPassword != "")
{
var token = WebSecurity.GeneratePasswordResetToken(OldLogin);
WebSecurity.ResetPassword(token, NewPassword);
}
User user = new User();
user.Id = Convert.ToInt32(rm.Id);
user.FullName = rm.Name;
user.Email = rm.Email;
user.Category = rm.UserCategory;
user.Login = rm.UserName;
string result = repo.UpdateUserDetails(user);
return RedirectToAction("Index");
}
然后它重定向到索引操作方法,该方法获取用户列表并将其传递回带有 WebGrid Helper 的视图。
每次我访问存储库时,我都会从 DbContext 对象中获取用户的最新值:
public List<User> GetAllUsersWithoutAdmin()
{
return context.Users.Where(x => x.Id != 1).OrderBy(x => x.FullName).ToList();
}
public User GetUser(int userId)
{
return context.Users.FirstOrDefault(x => x.Id == userId);
}
public string UpdateUserDetails(User user)
{
string info;
try
{
User uUser = context.Users.FirstOrDefault(x => x.Id == user.Id);
uUser.Category = user.Category;
uUser.Email = user.Email;
uUser.FullName = user.FullName;
uUser.Login = user.Login;
context.SaveChanges();
info = "success";
}
catch (Exception err)
{
info = err.Message;
}
return info;
}
我还使用 UoW 模式来解决在同一控制器中使用不同存储库的问题:
public interface IUnitOfWork
{
int SaveChanges();
}
然后每个存储库都实现此接口:
private ActivityLogContext context;
public UserRepository(IUnitOfWork _context)
{
context = _context as ActivityLogContext;
}
And shares it in the same context in the scope of the thread which is implemented in the Ninject Controller Factory by AddBindings() method:
private void AddBindings()
{
ninjectKernel.Bind<IActivityRepository>().To<ActivityRepository>();
ninjectKernel.Bind<IUserRepository>().To<UserRepository>();
ninjectKernel.Bind<ICategoryRepository>().To<CategoryRepository>();
ninjectKernel.Bind<IUnitOfWork>().To<ActivityLogContext>().InThreadScope();
}
A PROBLEM: For some strange reason, once every so often, when user object is being edited, context object presents wrong values for the user properties. It is happening on the level of EF somewhere between the DbContext and actual data. Especially, that data in SQL server is always right. It looks like EF is caching previous values for the properties and takes those instead of sourcing them from database. I have not observed when this behaviour exactly occurs, but it happens rather often - every second or third time when object is edited. Sometimes it happens couple of times in the row.
I have used the same setup in previous application and everything was fine. The only difference this time is that I'm using WebGrid Helper, and only pages with WebGrid Helper seem to cause this problem in my application???