奇怪的实体框架的行为 - 缓存? [英] Strange Entity Framework behaviour - caching?

查看:184
本文介绍了奇怪的实体框架的行为 - 缓存?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用EF 4.3迁移ASP.NET MVC 4 appliation。我使用的WebGrid助手来显示系统用户的详细信息:

I have ASP.NET MVC 4 appliation using EF 4.3 with migrations. I use a WebGrid Helper to display details for system users:

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

正如你所看到编辑操作方法负责编辑用户详细信息。这是如何通过视图模型到视图:

As you can see Edit action method is responsible for editing user details. This is how it passes the View Model to the view:

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

这是其如何保存的详细信息:

And this is how its saves the details:

    [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助手视图索引anction方法。

Then it redirects to Index anction method which sources list of users and passes it back to the View with WebGrid Helper.

我每次打我库源中最新的值从对​​象的DbContext用户:

Every single time I hit the repository I source the most recent values for users from DbContext object:

    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模式来解决在同一个控制器使用不同的存储库的问题:

Also I use UoW pattern to solve the problem of using different repositories in the same controller:

public interface IUnitOfWork
{
    int SaveChanges();
}

每个仓库将实现此接口:

Each repository then implements this interface:

    private ActivityLogContext context;

    public UserRepository(IUnitOfWork _context)
    {
        context = _context as ActivityLogContext;
    }

和股吧中这是在Ninject器厂由AddBindings)实现(线程的范围相同的上下文方法:

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


一个问题:
对于一些奇怪的原因,一旦每隔一段时间,当用户对象正在编辑,为用户属性上下文对象presents错误的价值观。它发生在EF的的DbContext和实际数据之间的电平的某个地方。特别是,在SQL Server的数据永远是正确的。它看起来像EF英孚教育为缓存的属性previous值,并采取那些不是从数据库采购他们。当这种行为正是发生我没有看到,但它发生,而经常 - 当对象被编辑每秒或第三次。有时它发生几次在行中。


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.

我已经使用在previous应用程序相同的设置,一切都很好。此时唯一的区别是,我使用的WebGrid助手,​​只有用的WebGrid助手页面似乎在我的应用程序?

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???

推荐答案

请问您的数据被正确渲染,如果你试试这个?

Does your data render correctly if you try this?

与AsNoTracking负载实体:

Load Entities with 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);
}

分离实体保存之后:

Detach Entities after saving:

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缓存。

This will give you detached entities which aren't tracked in the EF context, an approach that may or not be acceptable depending on your application. Even if you can't use it in the long run, give it a try to see if the problem is really the EF caching.

这篇关于奇怪的实体框架的行为 - 缓存?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆