我使用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>
)
})
如您所见,编辑操作方法负责编辑用户详细信息。这就是它将视图模型传递给视图的方式:
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");
}
然后它重定向到Index anction方法,该方法获取用户列表并将其传递回使用WebGrid Helper的View。
每次访问存储库时,我都会从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;
}
并通过AddBindings()方法在Ninject Controller Factory中实现的线程范围内的相同上下文中共享它:
private void AddBindings()
{
ninjectKernel.Bind<IActivityRepository>().To<ActivityRepository>();
ninjectKernel.Bind<IUserRepository>().To<UserRepository>();
ninjectKernel.Bind<ICategoryRepository>().To<CategoryRepository>();
ninjectKernel.Bind<IUnitOfWork>().To<ActivityLogContext>().InThreadScope();
}
问题: 出于某种奇怪的原因,每隔一段时间,当编辑用户对象时,上下文对象会为用户属性显示错误的值。它发生在DbContext和实际数据之间的EF级别。特别是,SQL服务器中的数据始终是正确的。看起来EF正在缓存属性的先前值,并采用这些值而不是从数据库中获取它们。我没有观察到这种行为何时确实发生,但它经常发生 - 每当第二次或第三次编辑对象时。有时它会连续发生几次。
我在之前的应用程序中使用了相同的设置,一切都很好。这次唯一的区别是我正在使用WebGrid Helper,只有带WebGrid Helper的页面似乎在我的应用程序中导致了这个问题???
答案 0 :(得分:1)
如果您尝试这样做,您的数据是否正确呈现?
使用AsNoTracking加载实体:
public List<User> GetAllUsersWithoutAdmin()
{
return context.Users.AsNoTracking().Where(x => x.Id != 1)
.OrderBy(x => x.FullName).ToList();
}
public User GetUser(int userId)
{
return context.Users.AsNoTracking().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();
// detach the entity after saving it
Context.Entry(uUser).State = System.Data.EntityState.Detached;
info = "success";
}
catch (Exception err)
{
info = err.Message;
}
return info;
}
这将为您提供未在EF上下文中跟踪的分离实体,根据您的应用程序,这种方法可能是可接受的,也可能是不可接受的。即使你不能长期使用它,试试看问题是否真的是EF缓存。
答案 1 :(得分:0)
我也注意到了这种行为。要演示Open View,请直接在dB中进行更改。 BANG您将看到更改未反映在您的视图中。
如果您从dB读取的上下文也是您用dB写入的上下文,那么EF会对数据进行缓存,并且只会“刷新”(这里选择错误的字)这个数据。
希望这能指出你正确的方向。