【问题标题】:ConcurrencyExeption on ASP.NET MVC ApplicationASP.NET MVC 应用程序上的 ConcurrencyExeption
【发布时间】:2017-11-08 18:34:22
【问题描述】:

问题简介

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

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

问题

当我想通过存储库系统更新帖子时会引发异常(并发异常),但我确信当您在帖子表中定义“[TimeStamp]”列类型时会发生这种类型的异常。我知道如何准确处理此异常,并且我确信没有人更新我当前正在更新的帖子,因为它适用于本地系统。我认为没有理由发生此异常,除了我不知道的原因,也许您现在可以帮助我。

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

组件

我有这个 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 泛型类;

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()
    {

    }
}

我有这个帖子存储库;

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 启动类;

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

我有这个帖子类

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

最后我有了这个 ViewPostModel;

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

【问题讨论】:

  • 检查这个答案我认为这将有助于解决您的问题:stackoverflow.com/questions/44070400/…
  • 感谢您的评论,但没有帮助。我在这里有非常不同的 senario。
  • 永远不要使用(有效的)静态的、长期存在的上下文。 这不是它的设计用途。实体框架上下文应该是短暂的,并在尽可能小的范围内处理(最好使用using 语句)。它永远不应该用于单独的请求/线程,并且不是线程安全的。保持长期的上下文没有任何好处。它只会带来问题(包括看起来像内存泄漏的问题)。查询数据库的成本远远超过了更新上下文的成本……这样做非常轻量级。
  • @spender 感谢您给我完美的体验。我会记住并立即尝试。我在想这将是保持 dbcontext 长期存在的问题。我还想问你一件事,为什么 microsoft IdentityFramework 演示项目在 OwinContext 中使用 DbContext ?还有这是身份所必需的还是一个错误?
  • @mjwills 我编辑了帖子,问题出在 AdminController 组件上。

标签: c# asp.net-mvc entity-framework asp.net-mvc-4 optimistic-concurrency


【解决方案1】:

我强烈怀疑您没有在更新方法中设置 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)
{

【讨论】:

  • 呜呜呜。我怎么能忘记这个。非常感谢你。它现在起作用了。一切都是因为映射器:)。我是第一次使用它。所以问题已经被你们解决了。谢谢大家帮忙。
猜你喜欢
  • 2011-08-22
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多