ConcurrencyExeption в приложении ASP.NET MVC
Введение в проблему
Прежде всего, я попробовал все, чтобы решить эту проблему безрезультатно. В настоящее время я впервые пытаюсь самостоятельно создать шаблон хранилища.
Мое приложение - это просто блог-сайт, и в нем есть несколько компонентов. Я прямо укажу на проблему для вас.
проблема
Когда я хочу обновить сообщение через систему репозитория, возникает исключение (исключение параллелизма), но я уверен, что этот тип исключения возникает при определении типа столбца "[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();
}
}
Я даю вам все, чтобы решить эту проблему.
Вот мои предположения и вопросы ##
- Может быть, где-то может быть состояние гонки, но как это возможно, я использую статический DbContext?
- Может быть, есть два запущенных экземпляра 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; }
}
1 ответ
Я сильно подозреваю, что вы не устанавливаете post.ID в вашем методе обновления. Вы можете убедиться в этом, проверив значение post.ID до postRepository.Update(post);
вызов.
Я подозреваю, что вам нужно изменить:
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)
{