Saving changes to user account result in DbUpdateConcurrencyException - c#

I have a form where the user can edit their user account information and then save the new changes.
The problem I'm getting happens when I save the modified changes to the database.
On the line context.SaveChanges(), I get a DbUpdateConcurrencyException exception thrown. It says, "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."
I have no idea why.
Here's what I have done:
public ActionResult EditUserAccount()
{
UserAccountViewModel editUserAccountViewModel = new UserAccountViewModel();
editUserAccountViewModel.UserName = UserSession.GetValue(StateNameEnum.UserName, StateNameEnum.UserName.ToString()) as string;
int UserId = WebSecurity.GetUserId(editUserAccountViewModel.UserName);
var userInfo = context.db_user.First(x => x.UserId == UserId);
editUserAccountViewModel.Title = userInfo.Title;
editUserAccountViewModel.FirstName = userInfo.FirstName;
editUserAccountViewModel.LastName = userInfo.LastName;
editUserAccountViewModel.PhoneNumber = userInfo.PhoneNumber;
editUserAccountViewModel.AltPhoneNumber = userInfo.AltPhoneNumber;
editUserAccountViewModel.EmailAddress = userInfo.EmailAddress;
editUserAccountViewModel.UserAccountState = UserAccountViewModel.AccountState.EDIT;
return (PartialView("~/Views/Account/UserAccount.cshtml", editUserAccountViewModel));
}
[HttpPost]
public ActionResult EditUserAccount_Save(UserAccountViewModel editUserAccountViewModel)
{
try
{
if (ModelState.IsValid)
{
editUserAccountViewModel.UserName = UserSession.GetValue(StateNameEnum.UserName, StateNameEnum.UserName.ToString()) as string;
db_user user = new db_user();
user.Title = editUserAccountViewModel.Title;
user.FirstName = editUserAccountViewModel.FirstName;
user.LastName = editUserAccountViewModel.LastName;
user.PhoneNumber = editUserAccountViewModel.PhoneNumber;
user.AltPhoneNumber = editUserAccountViewModel.AltPhoneNumber;
user.EmailAddress = editUserAccountViewModel.EmailAddress;
user.LanguageId = context.languages.Where(t => t.Code == editUserAccountViewModel.Language).Select(t => t.Id).SingleOrDefault();
user.CreatedDate = DateTime.Now;
user.UserId = WebSecurity.GetUserId(editUserAccountViewModel.UserName);
context.Entry(user).State = EntityState.Modified;
context.SaveChanges();
JsonResult res = Json(new { Success = true, data = "", Message = "" });
return res;
}
else
{
JsonResult res2 = Json(new { Success = false, data = "", Message = "" });
return res2;
}
}
return null;
}

You are not creating an instance of context within the controller action, which would imply that it is at the class level. That means that context is shared with every other web request processed by that controller. This part of the error message Entities may have been modified or deleted since entities were loaded seems to confirm that hypothesis.
Instead, create an instance of context in your controller action.
Since you are editing an existing user in this action, you will first need to load the existing user into the context from the database, rather than instantiating a new one as you are now.
I strongly suspect that this change will resolve your issue.
UPDATE
Here's a code example. I don't know what your context class is called, so you might have to change that part. I assume that the user must already exist when this controller is called (based on the name of the method). I removed the try because you are not catching anything. If there is something useful you can do when an exception is thrown, go ahead and put that back in.
[HttpPost]
public ActionResult EditUserAccount_Save(UserAccountViewModel editUserAccountViewModel)
{
if (ModelState.IsValid)
{
using (MyContext context = new MyContext())
{
int userId = WebSecurity.GetUserId(editUserAccountViewModel.UserName);
db_user user = context.DbUsers.Where(u => u.Id == userId).Single();
editUserAccountViewModel.UserName = UserSession.GetValue(StateNameEnum.UserName, StateNameEnum.UserName.ToString()) as string;
user.Title = editUserAccountViewModel.Title;
user.FirstName = editUserAccountViewModel.FirstName;
user.LastName = editUserAccountViewModel.LastName;
user.PhoneNumber = editUserAccountViewModel.PhoneNumber;
user.AltPhoneNumber = editUserAccountViewModel.AltPhoneNumber;
user.EmailAddress = editUserAccountViewModel.EmailAddress;
user.LanguageId = context.languages.Where(t => t.Code == editUserAccountViewModel.Language).Select(t => t.Id).SingleOrDefault();
user.CreatedDate = DateTime.Now;
context.SaveChanges();
JsonResult res = Json(new { Success = true, data = "", Message = "" });
return res;
}
}
else
{
JsonResult res2 = Json(new { Success = false, data = "", Message = "" });
return res2;
}
}

Related

ASP.NET Core - How to update existing record and insert a new one at the same time using Entity Framework

In ASP.NET Core-6 Web API Entity Framework, I want the application to perform update and insert on the same model in the database at the same time.
I have this code:
public async Task<Response<string>> CreateIdentiticationAsync(CreateIdentiticationDto model)
{
var response = new Response<string>();
using (var transaction = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
try
{
var identification = _mapper.Map<Identification>(model);
var existingIdentifications = await _dbContext.Identifications.Where(e => e.IsModified == false).ToListAsync();
foreach (var existingIdentification in existingIdentifications)
{
if (existingIdentification != null)
{
existingIdentification.IsModified = true;
_unitOfWork.UserIdentifications.Update(identification);
await _unitOfWork.Save();
}
}
Identification.IsModified = false;
Identification.Type = model.Type;
Identification.Name = model.Name;
await _unitOfWork.UserIdentifications.InsertAsync(identification);
await _unitOfWork.Save();
response.StatusCode = (int)HttpStatusCode.Created;
response.Successful = true;
response.Message = "Created Successfully!";
transaction.Complete();
return response;
}
catch (Exception ex)
{
transaction.Dispose();
response.Message = "An error occured";
response.Successful = false;
response.StatusCode = (int)HttpStatusCode.BadRequest;
return response;
}
}
}
When user wants to insert a new record, I want the application to first check the model, if no record exists it should just insert the new record.
But if it exists, it should update all the IsModified to true, and then go ahead and also insert a new record.
However, when no record exists, I was able to insert new record.
But where I have issue is that when it wants to update and insert new record, I got this error:
Violation of PRIMARY KEY constraint 'PK_identifications'. Cannot insert duplicate key in object 'dbo.identifications'. The duplicate key value is (81fe9b8d-2d9c-4d49-8f92-22afe043e327).
Note: Id is Guid and autgenerated
How do I resolve this?
Thanks
Many things to consider here, in modern EF, I would not use a unitOfWork also a transaction is not needed unless very specific cases, you should also validate the ID from your incoming model value is null since ID is supposed to be autogenerated (most likely this is the source of your error). Since I don't know the name of your PK field, I will not introduce such validation in my proposed code.
One last recommendation, avoid this code on your controller, it breaks Single Responsibility Principle. Create a layer where you perform your business tasks and call this layer from your controller.
Here is a simplified proposed code which should work, don't forget to ensure the value in the model ID is coming as null.
public async Task<Response<string>> CreateIdentiticationAsync(CreateIdentiticationDto model)
{
var response = new Response<string>();
try
{
var identification = _mapper.Map<Identification>(model);
var existingIdentifications = await _dbContext.Identifications.Where(e => e.IsModified == false).ToListAsync();
foreach (var existingIdentification in existingIdentifications)
{
existingIdentification.IsModified = true;
}
Identification.IsModified = false;
// If you already mapped this in line 6 why map those two fields again manually?
// Identification.Type = model.Type;
// Identification.Name = model.Name;
_dbContext.UpdateRange(existingIdentifications);
_dbContext.Add(identification);
await _dbContext.SaveChangesAsync();
response.StatusCode = (int)HttpStatusCode.Created;
response.Successful = true;
response.Message = "Created Successfully!";
return response;
}
catch (Exception ex)
{
transaction.Dispose();
response.Message = "An error occured";
response.Successful = false;
response.StatusCode = (int)HttpStatusCode.BadRequest;
return response;
}
}
public IActionResult Update(int? id,UpdateEmployeeVM employeeVM)
{
ViewBag.Positions = new SelectList(_context.Positions, nameof(Position.Id), nameof(Position.Name));
Employee existed=_context.Employees.Find(id);
if(existed==null) { NotFound();}
if (!_context.Positions.Any(p => p.Id == employeeVM.PositionId)) ModelState.AddModelError("PoitionId", "Choose Id right");
if (!ModelState.IsValid)
{
ViewBag.Positions = new SelectList(_context.Positions, nameof(Position.Id), nameof(Position.Name));
return View();
}
if (employeeVM.Image!=null)
{
string result = employeeVM.Image.CheckValidate("image/", 300);
if (result.Length > 0)
{
ViewBag.Positions=new SelectList(_context.Positions,nameof(Position.Id),nameof(Position.Name));
ModelState.AddModelError("Image", result);
}
existed.ImageUrl.DeleteFile(_env.WebRootPath, "assets/img");
existed.ImageUrl = employeeVM.Image.SaveFile(Path.Combine(_env.WebRootPath, "assets", "img"));
return View();
}
existed.PositionId=employeeVM.PositionId;
existed.FullName=employeeVM.FullName;
existed.ImageUrl = employeeVM.Image.SaveFile(Path.Combine(_env.WebRootPath, "assets", "img"));
_context.SaveChanges();
return RedirectToAction(nameof(Index));
}
public async Task<IActionResult> Create(CreateEmployeeVM employeeVM)
{
if (!_context.Positions.Any(p => p.Id == employeeVM.PositionId)) ModelState.AddModelError("PositionId", "bele bir position yoxdu");
if (!ModelState.IsValid)
{
ViewBag.Positions = new SelectList(_context.Positions, nameof(Position.Id), nameof(Position.Name));
return View();
}
string result = employeeVM.Image.CheckValidate(500,"image/");
if (result.Length > 0)
{
ViewBag.Positions = new SelectList(_context.Positions, nameof(Position.Id), nameof(Position.Name));
ModelState.AddModelError("Image", result);
return View();
}
Employee employee = new Employee
{
Name = employeeVM.Name,
Surname = employeeVM.Surname,
PositionId = employeeVM.PositionId,
FacebookUrl = employeeVM.FacebookUrl,
InstagramUrl = employeeVM.InstagramUrl,
TwitterUrl = employeeVM.TwitterUrl,
Salary = employeeVM.Salary,
ImageUrl = employeeVM.Image.SaveFile(Path.Combine(_env.WebRootPath, "assets", "img"))
};
await _context.Employees.AddAsync(employee);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}

Entity Framework "lost" a row after an error, can still navigate to row details

An application I'm working on at work had an interesting error that we couldn't track down and I've not been able to find anything similar on my searches.
My company has built a helpdesk system to track user issues, and after an error in submission the ticket "disappeared" from the list of all tickets. It was still visible in the database and was not filtered out anywhere. It was possible to navigate to the ticket by changing the URL to the ticket ID and all the details were the same as before the error in saving.
We ultimately solved the issue by restarting the web-app, but we'd like to track down the cause of the row disappearing from the list.
I've inherited this app and it has a whole host of issues we're already aware of, so I'm leaning towards the whole thing needing rebuilding from the ground up to make the save methods fully async instead of the half-and-half that we've currently got.
Not really sure what code to post as examples as the vast majority of the time it works, but obviously there's something not right in it.
EDITED TO ADD: Here's the edit post method from the controller
[HttpPost]
public async Task<ActionResult> Edit(EditTicketViewModel ticket)
{
try
{
var tech = (ticket.Technician_ID != null) ? this.UserService.Get(ticket.Technician_ID) : this.UserService.Get(this.User.Identity.GetUserId());
var cust = this.UserService.Get(ticket.Customer_ID);
var ogticket = this.TicketService.Get(ticket.Id);
var dateEdited = DateTime.UtcNow;
var productVersionId = OrganisationService.GetOrgProduct(ticket.OrgId, true).First(x => x.ProductID == ticket.ProductID).Product_Version.Id; ;
await this.TicketService.Edit(ticket.Id, ticket.Title, ticket.Description, dateEdited, ticket.Date_Closed, ticket.Customer_ID, ticket.State_Code, ticket.Priority_Code, ticket.Technician_ID, ticket.ProductID, productVersionId, ticket.Ticket_Type_ID);
if (ticket.State_Code == (int)StateCode.Closed)
{
await this.IntegrationService.SendEmailAsync(new EmailProperties()
{
Email = cust.Email,
Subject = "Ticket Closed",
Body = "Your ticket '{ticket.Title}' has now been closed.\n\n"//+
//$"Log into the portal to view it now -> <a href='https://helpdesk.rubixx.co.uk/Ticket/Details/{ticket.Id}'>Ticket {ticket.Id}</a>"
});
await this.IntegrationService.PrepareTeamsMessageAsync(new MessageProperties()
{
Summary = $"{this.UserService.Get(this.User).FullName} has closed a ticket",
Ticket_Id = ticket.Id,
Note_Id = null,
Type = TeamsMessageType.Closed
});
}
else await this.IntegrationService.PrepareTeamsMessageAsync(new MessageProperties()
{
Summary = $"{this.UserService.Get(this.User).FullName} has updated a ticket",
Ticket_Id = ticket.Id,
Note_Id = null,
Type = TeamsMessageType.Updated
});
this.TicketService.CreateTimelineEvent(ticket.Id, this.User.Identity.GetUserId(), DateTime.UtcNow.ToLocalTime(), "", TimelineEventType.TicketEdited);
this.AddToastMessage("Success", "Edited Successfully", ToastType.Success);
return Redirect(ticket.ReturnUrl);
}
catch (Exception ex)
{
this.IntegrationService.LogMessage($"Exception occurred: {ex.Message}");
this.AddToastMessage("Error: ", "An internal error has occurred", ToastType.Error);
return this.Redirect("/");
}
}
And the service function that actually saves the changes:
public async Task Edit(int ID, string Title, string Description, DateTime? dateedited, DateTime? dateclosed, string CustomerId, int StateCode, int Prioritycode, string TechnicianId, int Productid, int? productVersionId, int ticketType = (int)TicketTypeEnum.Support)
{
var originalTicket = Context.Tickets.Find(ID);
originalTicket.Title = Title;
originalTicket.Technician_ID = TechnicianId;
originalTicket.State_Code = ticketType == (int)TicketTypeEnum.FeatureRequest ? (int)Enums.StateCode.FeatureSuggestion : StateCode;
originalTicket.Priority_Code = ticketType == (int)TicketTypeEnum.FeatureRequest ? (int)PriorityCode.FeatureSuggestion : Prioritycode;
originalTicket.Description = Description;
originalTicket.Date_Edited = dateedited;
originalTicket.Date_Closed = dateclosed;
originalTicket.Customer_ID = CustomerId;
originalTicket.ProductID = Productid;
originalTicket.Product_Version_ID = productVersionId;
originalTicket.Ticket_Type_ID = ticketType;
await Context.SaveChangesAsync();
}
Here's the CreateTimelineEvent code:
public void CreateTimelineEvent(int ticketno, string raisedby, DateTime dateadded, string details, TimelineEventType type, string assignedto = null)
{
try
{
var timelineEvent = new TimelineEvent()
{
Ticket_Number = ticketno,
Raised_By = raisedby,
DateAdded = dateadded,
Details = details,
Type = (int)type,
Assigned_To = assignedto
};
Context.TimelineEvents.Add(timelineEvent);
Context.SaveChanges();
}
catch (Exception ex)
{
throw ex;
}
}
The GetTickets function:
public IEnumerable<Ticket> GetTickets(FilterType type, string current_user_id, TicketTypeEnum ticketType = TicketTypeEnum.Support)
{
IEnumerable<Ticket> tickets = null;
switch (ticketType)
{
case TicketTypeEnum.Support:
tickets = Context.Tickets.Include(e => e.Tech).Include(e => e.Customer).SupportTickets();
break;
case TicketTypeEnum.FeatureRequest:
tickets = Context.Tickets.Include(e => e.Tech).Include(e => e.Customer).FeatureRequestTickets();
break;
default:
tickets = Context.Tickets.Include(e => e.Tech).Include(e => e.Customer);
break;
}
switch (type)
{
case FilterType.OpenTickets:
return tickets.OpenTickets();
case FilterType.ClosedTickets:
return tickets.ClosedTickets();
case FilterType.MyOpenTickets:
return tickets.MyOpenTickets(current_user_id);
case FilterType.OpenedToday:
return tickets.OpenedToday();
case FilterType.DueToday:
return tickets.DueToday();
default:
return tickets;
}
}
Apologies for taking so long to get back to this question, but not long after I posted this I managed to track the issue down to a home-grown Dependency Injection system creating a static instance of the DBContext.
We've since decided to re-write the system in .Net Core to leverage the built in Dependency Injection.

SaveChanges not working on JsonResult method (UPDATE INFO)

The problem is basically the Save changes method is not working (updating), the method should receive 3 parameters, item id, user id and the object which contains the updated information from the UI, however the code seems to be something bad because the saveChanges() method is not working.
This is my code:
[HttpPost]
[AllowAnonymous]
public JsonResult UpdatePersonalData(int ItemId, int UserId, CND_PersonalData Item)
{
try
{
if (ModelState.IsValid)
{
using (var context = new DexusEntities())
{
CND_PersonalData PersonalData = context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
if (PersonalData == null)
{
/// Display bad request
/// User does not exist and/or is not activated
List<RootObject> rootObj = new List<RootObject>();
rootObj.Add(new RootObject
{
msg = "User/Item not found in our DB",
code = "error_07"
});
HttpContext.Response.StatusCode = 404;
HttpContext.Response.TrySkipIisCustomErrors = true;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
else
{
PersonalData = Item;
context.SaveChanges();
context.ChangeTracker.DetectChanges();
List<RootObject> rootObj = new List<RootObject>();
rootObj.Add(new RootObject
{
msg = "Information stored/updated successfully",
code = "success_05"
});
HttpContext.Response.StatusCode = 200;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
}
else
{
List<RootObject> rootObj = new List<RootObject>();
JsonRes.Issue = "The model is not correct";
rootObj.Add(new RootObject
{
msg = "Model is not valid",
code = "error_03"
});
HttpContext.Response.StatusCode = 403;
HttpContext.Response.TrySkipIisCustomErrors = true;// Avoid issues in the HTTP methods
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
catch (Exception ex)
{
string err = ex.ToString();
List<RootObject> rootObj = new List<RootObject>();
JsonRes.Issue = err;
rootObj.Add(new RootObject
{
msg = "Conflict with method, see issue description.",
code = "error_08"
});
HttpContext.Response.StatusCode = 400;// Bad request
HttpContext.Response.TrySkipIisCustomErrors = true;
JsonRes.Message = rootObj;
return Json(JsonRes, JsonRequestBehavior.AllowGet);
}
}
What's wrong with my code?
Thanks in advance.
As I can see you are not adding an item into the DbSet and calling SaveChanges after:
When adding an item you should put it into DbSet
context.CND_PersonalData.Add(item);
context.SaveChanges();
when you want to update just call SaveChanges after you update loaded object
var PersonalData= context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
PersonalData.Name = item.Name;
PersonalData.Title = item.Title;
context.SaveChanges();
You can't just assign passed object to an entity you got from the DB, you need to change properties. If you do it as you did you didn't change values in the loaded object. So when you call SaveChanges nothing is changed. You need to change properties one by one.
If you don't want to do that then you can attach your item into the db by using Attach method on context.
context.Attach(item);
context.SaveChanges();
but you should be careful because if you load and track item with the same id as you are doing before checking if it is null:
CND_PersonalData PersonalData = context.CND_PersonalData.Where(d => d.Id == ItemId && d.UserId == UserId).SingleOrDefault();
if (PersonalData == null)
{
then you will get an error during the save because the context is already tracking item with the same ID, so you can remove that check and just check if it exists:
if (context.CND_PersonalData.Any(d => d.Id == ItemId && d.UserId == UserId))
{
and then execute your code

Bug in order program in which payment can be bypassed

This project makes the customer first create an order and them has to pay for said order via Braintree, However the issue that I am getting is that a customer can create an order and them close the application. This will cause the order to still exist however the customer did not have to pay for their order. If any one knows of a work around for this their help would be thanked. (The orders and payments work. Its just this bug that I'm worried about)
Orders Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> FirstClassCreate(FormCollection values)
{
var order = new Order();
TryUpdateModel(order);
var customer = db.Users.FirstOrDefault(x => x.Email == User.Identity.Name);
var cart = ShoppingCart.GetCart(this.HttpContext);
try
{
Sets the order attributes
order.DeliveryDate = DateTime.Now.AddDays(1);
order.DeliveryMethod = "First Class";
order.FirstName = customer.FirstName;
order.LastName = customer.LastName;
order.PostalCode = customer.PostalCode;
order.State = customer.State;
order.City = customer.City;
order.Email = customer.Email;
order.Country = customer.Country;
order.Phone = customer.PhoneNumber;
order.Address = customer.Address;
order.Username = customer.Email;
order.OrderDate = DateTime.Now;
var currentUserId = User.Identity.GetUserId();
order.Total = cart.GetFirstClass();
if (order.SaveInfo && !order.Username.Equals("guest#guest.com"))
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
var ctx = store.Context;
var currentUser = manager.FindById(User.Identity.GetUserId());
//Save this back
//http://stackoverflow.com/questions/20444022/updating-user-data-asp-net-identity
//var result = await UserManager.UpdateAsync(currentUser);
await ctx.SaveChangesAsync();
await storeDB.SaveChangesAsync();
}
Saves the order to the database
//Save Order
storeDB.Orders.Add(order);
await storeDB.SaveChangesAsync();
//Process the order
cart = ShoppingCart.GetCart(this.HttpContext);
order.Total = cart.GetFirstClass();
order = cart.CreateOrder(order);
return RedirectToAction("FirstClass", "Checkouts");
}
catch
{
//Invalid - redisplay with errors
return View(order);
}
}
Checkouts controller
public ActionResult CreateFirstClass(FormCollection collection)
{
var gateway = config.GetGateway();
Decimal amount;
//Need to get the amount
try
{
amount = Convert.ToDecimal(Request["amount"]);
}
catch (FormatException e)
{
TempData["Flash"] = "Error: 81503: Amount is an invalid format.";
return RedirectToAction("New");
}
string nonceFromTheClient = collection["payment_method_nonce"];
var cart = ShoppingCart.GetCart(this.HttpContext);
//if (id == null)
//{
// return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
//}
//order = Orders.FindAsync(id);
Gets the necessary payment methods
var request = new TransactionRequest
{
Amount = cart.GetFirstClass(),
PaymentMethodNonce = nonceFromTheClient,
Options = new TransactionOptionsRequest
{
SubmitForSettlement = true
}
};
cart.EmptyCart();
Result<Transaction> result = gateway.Transaction.Sale(request);
if (result.IsSuccess())
{
Transaction transaction = result.Target;
return RedirectToAction("Show", new { id = transaction.Id });
}
else if (result.Transaction != null)
{
return RedirectToAction("Show", new { id = result.Transaction.Id });
}
else
{
string errorMessages = "";
foreach (ValidationError error in result.Errors.DeepAll())
{
errorMessages += "Error: " + (int)error.Code + " - " + error.Message + "\n";
}
TempData["Flash"] = errorMessages;
return RedirectToAction("New");
}
}
#

MembershipUser not getting updated result from database

I'm building a simple application where a user can edit their profile including adding/deleting a brand image. This seems to be working fine and is updating the database no problem, however when refreshing the page and retrieving the user details via Membership.GetUser() the result includes the old results and not those from the updated database.
Here is my MembershipUser GetUser override:
public override MembershipUser GetUser(string query, bool userIsOnline)
{
if (string.IsNullOrEmpty(query))
return null;
var db = (AccountUser)null;
// ...get data from db
if (query.Contains("#")){
db = _repository.GetByQuery(x => x.Email == query).FirstOrDefault();
}
else
{
string firstName = query;
string lastName = null;
if (query.Contains(" "))
{
string[] names = query.Split(null);
firstName = names[0];
lastName = names[1];
}
// ...get data from db
db = _repository.GetByQuery(x => x.FirstName == firstName && x.LastName == lastName).FirstOrDefault();
}
if (db == null)
return null;
ToMembershipUser user = new ToMembershipUser(
"AccountUserMembershipProvider",
db.FirstName + " " + db.LastName,
db.ID,
db.Email,
"",
"",
true,
false,
TimeStamp.ConvertToDateTime(db.CreatedAt),
DateTime.MinValue,
DateTime.MinValue,
DateTime.MinValue,
DateTime.MinValue);
// Fill additional properties
user.ID = db.ID;
user.Email = db.Email;
user.FirstName = db.FirstName;
user.LastName = db.LastName;
user.Password = db.Password;
user.MediaID = db.MediaID;
user.Media = db.Media;
user.Identity = db.Identity;
user.CreatedAt = db.CreatedAt;
user.UpdatedAt = db.UpdatedAt;
return user;
}
Note I am using a custom MembershipProvider and MembershipUser. Here is where I am calling that method:
public ActionResult Edit()
{
ToMembershipUser toUser = Membership.GetUser(User.Identity.Name, true) as ToMembershipUser;
Now when I do a separate query just under this line of code straight to the database, not invoking MembershipUser, I get the updated result which in turn updates the MembershipUser result?!
It seems it may be caching the results? Anyway around this? I hope this is clear enough. Thanks
Edit:
It appears that when I set a breakpoint just after :
// ...get data from db
db = _repository.GetByQuery(x => x.FirstName == firstName && x.LastName == lastName).FirstOrDefault();
'db' retrieves the outdated results though surely this is talking to the database? If need be I'll update with my repository pattern
I managed to find a workaround though I'm not happy with this solution, so if anyone can improve upon this please post.
I decided to manually update the MembershipUser instance manually each time I update the image. My controller now looks like this:
private static ToMembershipUser MembershipUser { get; set; }
// GET: Dashboard/AccountUsers/Edit
public ActionResult Edit()
{
if(MembershipUser == null)
MembershipUser = Membership.GetUser(User.Identity.Name, true) as ToMembershipUser;
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
public JsonResult UploadMedia(IEnumerable<HttpPostedFileBase> files, int id)
{
var images = new MediaController().Upload(files);
if (images == null)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("File failed to upload.");
}
AccountUser accountUser = db.AccountUsers.Find(id);
db.Entry(accountUser).State = EntityState.Modified;
accountUser.UpdatedAt = TimeStamp.Now();
accountUser.MediaID = images[0];
db.SaveChanges();
MembershipUser.Media = accountUser.Media;
MembershipUser.MediaID = accountUser.MediaID;
return Json(new { result = images[0] });
}
[HttpPost]
[ValidateJsonAntiForgeryToken]
public JsonResult DeleteMedia(int id)
{
bool delete = new MediaController().Delete(id, 1);
if (!delete)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json("Error. Could not delete file.");
}
MembershipUser.Media = null;
MembershipUser.MediaID = null;
return Json("Success");
}

Categories