ASP.NET MVC 应用程序的 ConcurrencyExeption

ConcurrencyExeption on ASP.NET MVC Application

问题简介

首先我想尽一切办法解决这个问题,但没有结果。我目前正在尝试第一次自己设计存储库模式。

我的应用程序只是一个博客网站,它有一些组件。我直接给你指出问题

问题

当我想通过存储库系统更新 post 时抛出异常(并发异常),但我确信当您在 [= 中定义“[TimeStamp]”列类型时会发生此类异常84=] Table。我知道如何准确处理此异常,并且我确信没有人更新我当前正在更新的 post,因为它适用于本地系统。我认为除了一个我不知道的原因之外没有理由发生这个异常,也许你可以在这一点上帮助我。

我明确地为你定义了问题,然后让我们开始代码块;

组件

我有这个 AdminController

public class AdminController : Controller
{
    private IDbFactory _dbFactory;
    private IUnitOfWork _unitOfWork;

    private ICategoryRepository _categoryRepository;
    private IPostRepository _postRepository;
    private ITagRepository _tagRepository;

    public ICategoryRepository categoryRepository
    {
        get
        {
            return _categoryRepository ?? (_categoryRepository = new CategoryRepository(HttpContext.GetOwinContext().Get<DbFactory>()));
        }
        set
        {
            _categoryRepository = value;
        }
    }
    public IPostRepository postRepository
    {
        get
        {
            return _postRepository ?? (_postRepository = new PostRepository(HttpContext.GetOwinContext().Get<DbFactory>()));
        }

        set
        {
            _postRepository = value;
        }
    }
    public ITagRepository tagRepository
    {
        get
        {
            return _tagRepository ?? (_tagRepository = new TagRepository(HttpContext.GetOwinContext().Get<DbFactory>()));
        }

        set
        {
            _tagRepository = value;
        }
    }
public IDbFactory dbFactory
    {
        get
        {
            return _dbFactory ?? (_dbFactory = 
           HttpContext.GetOwinContext().Get<DbFactory>());
        }
    }
    public IUnitOfWork unitOfWork
    {
        get
        {
            return _unitOfWork ?? (_unitOfWork = 
           HttpContext.GetOwinContext().Get<UnitOfWork>());
        }
    }
[HttpPost]
    [ValidateAntiForgeryToken]
    [ValidateInput(false)]
    public ActionResult UpdatePost([Bind(Include = "IntroText, PostText, CodeText, Header, Author, ImagePath, CategoryID")] ViewPostModel model)
    {
        if (ModelState.IsValid)
        {
            Post post = new Post();
            post = Mapper.Map<ViewPostModel, Post>(model);

            if (model.CodeText != null)
                post.PostText = GetCodedPostText(model.PostText, model.CodeText);

            post.CreatedDate = DateTime.Now.ToShortDateString();
            post.CategoryID = model.CategoryID;
            postRepository.Update(post);
            unitOfWork.SaveChanges(); // Throws and exception (Concurrency Exception)
        }
        ViewBag.Categories = FillCategoriesForDropdownList();
        return RedirectToAction("DetailPost");
    }
}

我有这个通用的 RepositoryBase class;

private IDbFactory dbFactory;
    private AppDbContext context;
    private ICategoryRepository _categoryRepository;
    private IPostRepository _postRepository;
    private ITagRepository _tagRepository;

    //public ICategoryRepository categoryRepository
    //{
    //    get
    //    {
    //        return _categoryRepository ?? (_categoryRepository = new CategoryRepository(HttpContext.Current.GetOwinContext().Get<DbFactory>()));
    //    }
    //    set
    //    {
    //        _categoryRepository = value;
    //    }
    //}
    //public IPostRepository postRepository
    //{
    //    get
    //    {
    //        return _postRepository ?? (_postRepository = new PostRepository(HttpContext.Current.GetOwinContext().Get<DbFactory>()));
    //    }

    //    set
    //    {
    //        _postRepository = value;
    //    }
    //}
    //public ITagRepository tagRepository
    //{
    //    get
    //    {
    //        return _tagRepository ?? (_tagRepository = new TagRepository(HttpContext.Current.GetOwinContext().Get<DbFactory>()));
    //    }

    //    set
    //    {
    //        _tagRepository = value;
    //    }
    //}

    AppDbContext db
    {
        get
        {
            return context ?? (context = dbFactory.Init());
        }
    }

    public ICategoryRepository categoryRepository
    {
        get
        {
            throw new NotImplementedException();
        }

        set
        {
            throw new NotImplementedException();
        }
    }

    public IPostRepository postRepository
    {
        get
        {
            throw new NotImplementedException();
        }

        set
        {
            throw new NotImplementedException();
        }
    }

    public ITagRepository tagRepository
    {
        get
        {
            throw new NotImplementedException();
        }

        set
        {
            throw new NotImplementedException();
        }
    }

    public static UnitOfWork Create()
    {
        return new UnitOfWork(HttpContext.Current.GetOwinContext().Get<DbFactory>());
    }

    public UnitOfWork(IDbFactory _dbFactory)
    {
        dbFactory = _dbFactory;
    }

    public void SaveChanges()
    {
        db.SaveChanges();
    }

    public void Dispose()
    {

    }
}

我有这个 Post 存储库;

public class PostRepository : RepositoryBase<Post>, IPostRepository, IDisposable
{
    public PostRepository(IDbFactory dbFactory) : base(dbFactory) { }

    public static PostRepository Create()
    {
        return new PostRepository(HttpContext.Current.GetOwinContext().Get<DbFactory>());
    }

    public void Dispose()
    {

    }
}

我有这个数据库初始化器;

public class AppDbInitializer : DropCreateDatabaseAlways<AppDbContext>
{
    protected override void Seed(AppDbContext context)
    {
        SeedIdentity(context);
        SeedTables(context);
        base.Seed(context);
    }

    private void SeedIdentity(AppDbContext context)
    {
        //var userManager = HttpContext.Current.GetOwinContext().GetUserManager<AppUserManager>();
        //var roleManager = HttpContext.Current.GetOwinContext().Get<AppRoleManager>();
        const string name = "admin@example.com";
        const string password = "SelcuK99.";
        const string roleName = "Admin";

        #region Old
        //var role = roleManager.FindByName(roleName);
        //AppRole role = null;
        //if (role == null)
        //{
        //    role = new AppRole(roleName);
        //    var roleresult = roleManager.Create(role);
        //}
        //AppUser user = null;
        ////var user = userManager.FindByName(name);
        //if (user == null)
        //{
        //    user = new AppUser { UserName = name, Email = name };
        //    var result = userManager.Create(user, password);
        //    result = userManager.SetLockoutEnabled(user.Id, false);
        //}

        //var rolesForUser = userManager.GetRoles(user.Id);
        //if (!rolesForUser.Contains(role.Name))
        //{
        //    var result = userManager.AddToRole(user.Id, role.Name);
        //}
        #endregion

        RoleStore<AppRole> roleStore = new RoleStore<AppRole>(context);
        RoleManager<AppRole> roleManager = new RoleManager<AppRole>(roleStore);
        AppRole role = new AppRole
        {
            Name = roleName
        };
        roleManager.Create(role);

        UserStore<AppUser> userStore = new UserStore<AppUser>(context);
        AppUserManager userManager = new AppUserManager(userStore);
        AppUser user = new AppUser { Email = name, UserName = name};
        userManager.Create(user, password);
        userManager.AddToRole(user.Id, roleName);
    }
}

我有这个 OwinContext 启动 class;

    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.CreatePerOwinContext(AppDbContext.Create);
            app.CreatePerOwinContext(DbFactory.Create);
            app.CreatePerOwinContext(TagRepository.Create);
            app.CreatePerOwinContext(CategoryRepository.Create);
            app.CreatePerOwinContext(PostRepository.Create);
            app.CreatePerOwinContext(UnitOfWork.Create);
            app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);
            app.CreatePerOwinContext<AppRoleManager>(AppRoleManager.Create);
            app.CreatePerOwinContext<AppSignInManager>(AppSignInManager.Create);

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = 
    DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {  
                    OnValidateIdentity = 
    SecurityStampValidator.OnValidateIdentity<AppUserManager, AppUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => 
    user.GenerateUserIdentityAsync(manager))
                }
            });



  app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
        }   
    }

这是 AppDbContext

public class AppDbContext : IdentityDbContext<AppUser>
    {
        public AppDbContext() : base("AppDbContext", throwIfV1Schema: false) { }

        public static AppDbContext Create()
        {
            return new AppDbContext();
        }

        public DbSet<Category> Categories { get; set; }
        public DbSet<Post> Posts { get; set; }
        public DbSet<Tag> Tags { get; set; }

        static AppDbContext()
        {
            Database.SetInitializer(new AppDbInitializer());
        }

        //protected override void OnModelCreating(DbModelBuilder modelBuilder)
        //{
        //    modelBuilder.Configurations.Add(new CategoryConfiguration());
        //    modelBuilder.Configurations.Add(new PostConfiguration());
        //}
    }

我有这个Postclass

public class Post : BaseEntity, IAudit
    {
        public int CategoryID { get; set; }
        public string IntroText { get; set; }
        public string PostText { get; set; }
        public string CodeText { get; set; }
        public string Header { get; set; }
        public string Author { get; set; }
        public string ImagePath { get; set; }
        public string CreatedDate { get; set; }
        public string UpdatedDate { get; set; }
        public virtual ICollection<PostTagMapping> PostTags { get; set; }
        public Category Category { get; set; }
    }

最后我有了这个视图Post模型;

public class ViewPostModel : BaseEntity
    {
        public string PostText { get; set; }
        public string IntroText { get; set; }
        public string CodeText { get; set; }
        public string Author { get; set; }
        public string Header { get; set; }
        public string ImagePath { get; set; }
        public DateTime? CreatedDate { get; set; }
        public DateTime? UpdatedDate { get; set; }
        public int CategoryID { get; set; }
    }

我忘了给你 DbFactory;

public class DbFactory : Disposable, IDbFactory
    {
        private AppDbContext context;

        public static DbFactory Create()
        {
            return new DbFactory();
        }

        public AppDbContext Init()
        {
            int a;
            if (context == null)
                a = 5;
            return (HttpContext.Current.GetOwinContext().Get<AppDbContext>());
        }

        protected override void DisposeCore()
        {
            if (context != null)
                context.Dispose();
        }
    }

我给你解决这个问题的一切。

这是我的假设和问题##

  1. 也许某个地方可能存在竞争条件,但我使用静态 DbContext 怎么可能?
  2. 也许有两个 运行 DbContext 实例,但我又怎么可能使用静态 DbContext?

这是异常的详细信息

InnerException 消息: 存储更新、插入或删除语句影响了意外数量的行 (0)。自加载实体后,实体可能已被修改或删除。有关理解和处理乐观并发异常的信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=472540

堆栈跟踪:

at System.Data.Entity.Internal.InternalContext.SaveChanges()
   at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
   at System.Data.Entity.DbContext.SaveChanges()
   at HybridBlog.Model.RepositoryBase`1.Update(TEntity entity) in D:\MVC_Projects\TrialProjects\HybridBlog\HybridBlog.Model\RepositoryBase.cs:line 71
   at HybridBlog.Web.Controllers.AdminController.UpdatePost(ViewPostModel model) in D:\MVC_Projects\TrialProjects\HybridBlog\HybridBlog.Web\Controllers\AdminController.cs:line 153
   at lambda_method(Closure , ControllerBase , Object[] )
   at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()
   at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()

BaseEntity.cs

public class BaseEntity
    {
        public int ID { get; set; }
    }

我强烈怀疑您没有在更新方法中设置 post.ID。您可以通过在调用 postRepository.Update(post); 之前检查 post.ID 的值来验证这一点。

我怀疑你需要更改:

public ActionResult UpdatePost([Bind(Include = "IntroText, PostText, CodeText, Header, Author, ImagePath, CategoryID")] ViewPostModel model)
{

至:

public ActionResult UpdatePost([Bind(Include = "ID, IntroText, PostText, CodeText, Header, Author, ImagePath, CategoryID")] ViewPostModel model)
{