Violation of UNIQUE KEY constraint on Update in ASP.net MVC - asp.net

Can someone please check out this code, i really dont understand why i got violation of unique when i try to update an record. the code used to create new record work just fine, but when i try to use it to update, it called out violation.
Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(User user)
{
if (ModelState.IsValid)
{
userRepository.SaveUser(user);
return RedirectToAction("List");
}
else
return View("Edit");
}
userRepo:
public void SaveUser(User user)
{
user.LAST_ACTIVITY = DateTime.Now;
if (user.USER_ID != 0)
{
usersTable.Attach(user);
usersTable.Context.Refresh(RefreshMode.KeepCurrentValues, user);
}
else
{
usersTable.InsertOnSubmit(user);
}
usersTable.Context.SubmitChanges();
}
and i got an error:
Unable to refresh the specified
object. The object no longer exists
in the database.
when i try to change the userRepo like this for testing purpose.
public void SaveUser(User user)
{
user.LAST_ACTIVITY = DateTime.Now;
usersTable.Attach(user);
usersTable.Context.Refresh(RefreshMode.KeepCurrentValues, user);
usersTable.Context.SubmitChanges();
}
Im wondering if there anyone on this board can find out if i am wrong somewhere in this problem :).
Thank you very much and wish you best regard. :)

Looks like you have conflicts to resolve even though you're telling it to "KeepCurrentValues", try this before the submit changes...
foreach(ObjectChangeConflict conflict in usersTable.Context.ChangeConflicts)
{
foreach(MemberChangeConflict memberConflict in conflict.MemberConflicts)
{
memberConflict.Resolve(RefreshMode.KeepCurrentValues);
}
}

Ignore ID on your model binding.
[Bind(Exclude= "Id")]
public ActionResult Edit(User user)
Kindness,
Dan

Related

accessing virtual actionresult in mvc

I want to know how can I access virtual actionresult, since I haven't seen so far this type of actionresults. I've read little bit and I can see that is related to t4mvc but I'm not sure how can I access it.
This is what I have, ScheduleController, which has this actionresult for example:
[Authorize]
public virtual ActionResult AdminSport(int sportId)
{
Sport sport = _rep.GetSport(sportId);
if(sport == null)
{
return this.ViewNotFound();
}
if(!User.IsScheduleAdmin(sport))
{
return this.ViewNotAuthorized();
}
var ret = _rep.ListScheduleEntriesForAD(sport);
return View(ret);
}
Then, the only other instance of that controller I found was in T4MVC, and this is whats in that file:
[NonAction]
partial void AdminSportOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int sportId);
[NonAction]
public override System.Web.Mvc.ActionResult AdminSport(int sportId)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.AdminSport);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "sportId", sportId);
AdminSportOverride(callInfo, sportId);
return callInfo;
}
My question is how can I access that specific action, for example if I type in the browser: /Schedule/AdminSport I'm getting an error.
Any idea what/how do I need to fix this?

MVC3 logged in User can see only own stuff apart from Admin

A novice to asp.net and mvc3. I am learning by setting myself challenges/developing an application. I tag all record tables where users interact with ProviderUserKey. Now I want to be able to restrict users logged in to be able to edit or delete their own records only but administrators can edit or delete any. I have been using scaffolding to generate controllers and views etc. for eg code for editing`// POST: /Post/Edit/5
[HttpPost]
public ActionResult Edit(PJpost pjpost)
{
if (ModelState.IsValid)
{
db.Entry(pjpost).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(pjpost);
}`
Any help will be highly appreciated.
If you have a generic Edit method/action and you would like to keep it that way, I would add a method in your controller somethink like ValidateOwnership(record). This method would need to verify if CurrentUser's ID is matching the one on the record and if user is a member of particular role - that can be done with RoleManager class. Method would return true/false.
When you got it ready just put the call to the method in your code after ModelState validation. It would look like this
[HttpPost]
public ActionResult Edit(PJpost pjpost)
{
if (ModelState.IsValid)
{
if(IsOwnershipValid(pjpost){
db.Entry(pjpost).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
else {
ModelState.AddModelError("ERROR","You're not allowed to do that");
return View(pjpost);
}
}
return View(pjpost);
}
EDIT :
So the OwnershipValidation could look like this :
public bool ValidateOwnership(Pjpost pjpost) {
if (pjpost.MemUID == Membership.GetUser().ProviderUserKey.ToString())
{
return true;
}
else
{
return false;
}
}
I hope this is what you meant.
You need to look in to user roles and the process of authorization usually, MVC provides a registration and log in in it template including the account controller. To restrict user access you have to assign roles to users.
the code behind it would look something like this.
[Authorize(Roles="admin")]
public ActionResult admin()
{
//Action gives an admin rights since the user is in the admin role
return View();
}
[Authorize(Roles="manager")]
public ActionResult manager()
{ //give a managers rights since user is im managers roles.
return View();
}

How to save change with MVC 2 en EF 4?

I'm using MVC 2 with EF4. Creating or deleting objects works but update doesn't.
I have read lot and lot tutorials / questions on StackOverflow, but I haven't found a real WORKING code to use in my "Edit" method.
[HttpPost]
public ActionResult Edit(int id, Account model)
{
try
{
Account accountEdited = accountRepository.Get(id);
// Working code to update "accountEdited" with "model"'s values ???
accountRepository.Save();
return RedirectToAction("Details", new { id = id });
}
catch (Exception ex)
{
return View();
}
}
I'm using EntityFramework with WCF Data Service
This is what I do:
[HttpPost]
public ActionResult Edit(int id, Account model)
{
try
{
Account accountEdited = accountRepository.Get(id);
TryUpdateModel(accountEdited);
ctx.SaveChanges();
return RedirectToAction("Details", new { id = id });
}
catch (Exception ex)
{
return View();
}
}
The initial call to the repository will ensure the entity is in the graph, in an Unmodified state. MVC's built in TryUpdateModel method will then merge the two objects together (the accountEdited object, and the form post data that has been model bound).
This will result in the entity being in a Modified state.
Simply calling SaveChanges() on the object context will then push the changes to the database.
I have dabbled in techniques such as the "stub technique" but it introduced a world of pain (mainly to do with relationships), so this is the easiest approach, and works well.
You have your real EF work abstracted from you code you posted. Here is the simplest EF save:
public void Save(Account account)
{
using (DBContext ctx= new DBContext ())
{
ctx.Attach(account);
ctx.SaveChanges();
}
}
You only need to attach the object if it was obtained in another context. If not you can do it like:
public void Save(int AccountID)
{
using (DBContext ctx= new DBContext ())
{
Account account = ctx.Account.Single(a => a.ID == AccountID)
account.property = somepropchange;
ctx.SaveChanges();
}
}

Spring MVC Validation - Avoiding POST-back

I'd like to validate a Spring 3 MVC form. When an element is invalid, I want to re-display the form with a validation message. This is pretty simple so far. The rub is, when the user hits refresh after an invalid submission, I don't want them to POST, I want them to GET. This means I need to do a redirect from the form POST (submission) to re-display the form with validation messages (the form is submitted via a POST).
I'm thinking the best way to do this is to use SessionAttributeStore.retrieveAttribute to test if the form is already in the user's session. If it is, use the store form, otherwise create a new form.
Does this sound right? Is there a better way to do this?
To solve this problem, I store the Errors object in the session after a redirect on a POST. Then, on a GET, I put it back in the model. There are some holes here, but it should work 99.999% of the time.
public class ErrorsRedirectInterceptor extends HandlerInterceptorAdapter {
private final static Logger log = Logger.getLogger(ErrorsRedirectInterceptor.class);
private final static String ERRORS_MAP_KEY = ErrorsRedirectInterceptor.class.getName()
+ "-errorsMapKey";
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView mav)
throws Exception
{
if (mav == null) { return; }
if (request.getMethod().equalsIgnoreCase(HttpMethod.POST.toString())) {
// POST
if (log.isDebugEnabled()) { log.debug("Processing POST request"); }
if (SpringUtils.isRedirect(mav)) {
Map<String, Errors> sessionErrorsMap = new HashMap<String, Errors>();
// If there are any Errors in the model, store them in the session
for (Map.Entry<String, Object> entry : mav.getModel().entrySet()) {
Object obj = entry.getValue();
if (obj instanceof Errors) {
if (log.isDebugEnabled()) { log.debug("Adding errors to session errors map"); }
Errors errors = (Errors) obj;
sessionErrorsMap.put(entry.getKey(), errors);
}
}
if (!sessionErrorsMap.isEmpty()) {
request.getSession().setAttribute(ERRORS_MAP_KEY, sessionErrorsMap);
}
}
} else if (request.getMethod().equalsIgnoreCase(HttpMethod.GET.toString())) {
// GET
if (log.isDebugEnabled()) { log.debug("Processing GET request"); }
Map<String, Errors> sessionErrorsMap =
(Map<String, Errors>) request.getSession().getAttribute(ERRORS_MAP_KEY);
if (sessionErrorsMap != null) {
if (log.isDebugEnabled()) { log.debug("Adding all session errors to model"); }
mav.addAllObjects(sessionErrorsMap);
request.getSession().removeAttribute(ERRORS_MAP_KEY);
}
}
}
}
It's not clear from your question but it sounds like your GET and POST actions are mapped to the same handler. In that case you can do something like:
if ("POST".equalsIgnoreCase(request.getMethod())) {
// validate form
model.addAttribute(form);
return "redirect:/me.html";
}
model.addAttribute(new MyForm());
return "/me.html";
In the JSP check if there are any error on the form and display as needed.
Such approach is called PRG (POST/REdirect/GET) design pattern I explained it few days ago as one of the answers:
Spring MVC Simple Redirect Controller Example
Hope it helps :)

HttpRuntime Close does not remove items from the Cache as advertised

I've created my own cache manager for a web site I'm developing and I was looking to find the best way to clear the cache under certain circumstances.
I found many articles saying the proper way to clear the cache is to call HttpRuntime.Close()
However, in my unit tests setup I call the encapsulated function HttpRuntime.Close() and the cache is NOT being cleared out.
I expected it to perform something similar to
foreach (DictionaryEntry cacheItem in HttpRuntime.Cache)
{
HttpRuntime.Cache.Remove(cacheItem.Key.ToString());
}
The foreach loop works great in my encapsulated function, but the Close() never works right.
Am I misunderstanding the purpose of HttpRuntime.Close() or is there something more sinister going on here?
Don't use Close, it does more than the docs say. And the docs also say not to use it while processing normal requests...
This is the reflected source of Close():
[SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
public static void Close() {
if (_theRuntime.InitiateShutdownOnce()) {
SetShutdownReason(ApplicationShutdownReason.HttpRuntimeClose, "HttpRuntime.Close is called");
if (HostingEnvironment.IsHosted) {
HostingEnvironment.InitiateShutdown();
} else {
_theRuntime.Dispose();
}
}
}
Also, you cannot iterate over a collection and remove items from it at the same time, as this renders the enumeration invalid.
So, try this instead, which doesn't change what it loops over:
List<string> toRemove = new List<string>();
foreach (DictionaryEntry cacheItem in HttpRuntime.Cache) {
toRemove.Add(cacheItem.Key.ToString());
}
foreach (string key in toRemove) {
HttpRuntime.Cache.Remove(key);
}
That being said, really, you should try to use cache dependencies to have the invalid cache entries cleared automatically for you, and then all this becomes unnecessary.
I understand the issue with enumeration but for some reason the Cache doesn't seem to have a problem removing an item while walking through the list.
If you drill down to the detail implementation, you will find the Enumerator is created by CacheSingle.CreateEnumerator, a new Hashtable instance is created for enumeration.
That's why you can do the remove in a foreach loop.
you could simply implement your own Cache class, check the below one:
public sealed class YourCache<T>
{
private Dictionary<string, T> _dictionary = new Dictionary<string, T>();
private YourCache()
{
}
public static YourCache<T> Current
{
get
{
string key = "YourCache|" + typeof(T).FullName;
YourCache<T> current = HttpContext.Current.Cache[key] as YourCache<T>;
if (current == null)
{
current = new YourCache<T>();
HttpContext.Current.Cache[key] = current;
}
return current;
}
}
public T Get(string key, T defaultValue)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException("key should not be NULL");
T value;
if (_dictionary.TryGetValue(key, out value))
return value;
return defaultValue;
}
public void Set(string key, T value)
{
if (key == null)
throw new ArgumentNullException("key");
_dictionary[key] = value;
}
public void Clear()
{
_dictionary.Clear();
}
}
you could call items from cache or even clear them using the following:
// put something in this intermediate cache
YourCache<ClassObject>.Current.Set("myKey", myObj);
// clear this cache
YourCache<ClassObject>.Current.Clear();

Resources