My create and delete operations are working well. But, the Edit function is giving the following error :- 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.
NOTE:- CatPicView is a ViewModel merging the two entities Category and Picture
Following is the code for my Edit action code :-
[HttpPost]
public ActionResult Edit(CatPicView catPic)
{
if (ModelState.IsValid)
{
if (!String.IsNullOrEmpty(catPic.Picture.PictureUrl))
{
if (catPic.Category.PictureId == null)
{
Picture picture = new Picture();
picture.PictureUrl = catPic.Picture.PictureUrl;
db.Pictures.Add(picture);
catPic.Category.PictureId = picture.Id;
}
else
{
db.Entry(catPic.Picture).State = EntityState.Modified;
}
}
db.Entry(catPic.Category).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ParentCategoryId = new SelectList(db.Categories, "Id", "Name", catPic.Category.ParentCategoryId);
return View(catPic);
}
Using the debuger, check the properties of the object you are trying to update. The most likely is that you have an ID in null.
To fix this, you should place a hidden field holding the id of the modified object so when posting the form it became mapped to your object.
You are using an ID that does not exist in the current context which is picture.Id. At the time that you are using it an ID has not yet been generated, add db.SaveChanges before attempting to use the ID.
if (catPic.Category.PictureId == null)
{
Picture picture = new Picture();
picture.PictureUrl = catPic.Picture.PictureUrl;
db.Pictures.Add(picture);
db.SaveChanges();
catPic.Category.PictureId = picture.Id;
}
Related
I am very new to c# and asp.net mvc. I'm building a HR portal for our company where a user can submit a leave form among other things... So I'm using mssql as the database server and using Entity Frame work to communicate with it. I have 3 entities, user (Containing user details), permissions (the user permissions for allowing actions in the app) and then the leave form table (where the leave form details are stored). There is a one to many relationship between user - permission and then a one to many relationship between user-leave. I am not fazed about the permissions as that gets created when the user account is being created.
The problem I am facing is, how do I add a leave form for a specific user? Below is my controller code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Leave(MasterViewModel model)
{
DocSubViewModel mv = model.DSModel;
int userId = Convert.ToInt32(Session["userID"]);
try
{
using (HrDcpDBContainer db = new HrDcpDBContainer())
{
var leave = db.leaves.Create();
leave.dateFrom = mv.DateFrom;
leave.dateSubmitted = DateTime.Now;
leave.dateTo = mv.DateTo;
leave.nrDays = mv.NrDays;
leave.reason = mv.SpecialLeave;
leave.TLApproval = null;
leave.TLApprovalDate = null;
leave.TLApprovalID = mv.TeamLeaderID;
leave.DMApprovalDate = null;
leave.DMApprovalID = mv.DepManagerID;
leave.DMApproval = null;
leave.type = mv.Type;
leave.user = userId;
db.leaves.Add(leave);
db.SaveChanges();
}
ViewBag.Message = "Leave Form submitted Successfully. You will be redirected shortly...";
return View("result");
}
catch (Exception ex)
{
ViewBag.Message = ex;
//ViewBag.Message = "Leave Form submitted Successfully. You will be redirected shortly...";
return View("result");
}
The problem comes in leave.user = userId;. It says:
Cannot implicitly convert int to Portal.Model.user
I can't seem to find out how to do this...
You're telling it to put the UserId where your leave model is asking for a User.
Your relationship requires a User to go in there, so you'll have to update your code a little bit:
using (HrDcpDBContainer db = new HrDcpDBContainer())
{
var leave = db.leaves.Create();
leave.user = db.users.First(x => x.Id == userId);
}
This will put reference to the actual user in the new leave record. If you go later and check it out you'll see a column in the leave table called user_Id that has an integer value in it and is set as a foreign key to the users table.
Note that this will error if no user exists having the specified Id value. If you anticipate this to be a problem, rather use .FirstOrDefault() instead of .First() and then account for the value being null before you add it to your new leave object.
That's expected since User is a object and not int. What you should be doing probably is leave.user.UserId = userId; instead [Assuming leave.user is of type User which has a UserId property]
When I'm editing a "salesmember" and I'm trying to save the new file path / or old file path, based on user input, it should either overwrite the image, or it will use the previous image stored in the DB.
But, when I try to modify the entity state, before I save the changes in my SQL Server, I get the error:
An exception of type 'System.InvalidOperationException' occured in EntityFramework.dll but was not handled in user code. Additional information: Attaching an entity of type 'SalesMember' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
I'm modifying the SalesMember with that primary key. Which, it saves the image locally, but it won't save the DB row.
My Edit Action -----
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="SalesMemberID,FirstName,LastName,PageName,CellPhone,Email,InactiveRedirectTo,CustomText,Photo,Active, Position")] SalesMember salesmember, HttpPostedFileBase file)
{
SalesMember SalesPhoto = db.SalesMembers.Find(salesmember.SalesMemberID);
salesmember.Photo = saveImage(file, salesmember, SalesPhoto);
if (ModelState.IsValid)
{
salesmember.AddDate = SalesPhoto.AddDate;
salesmember.UpdateDate = DateTime.Now;
salesmember.IPAddress = Request.UserHostAddress;
salesmember.AddUser = "admin";
salesmember.UpdateUser = "admin";
db.Entry(salesmember).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(salesmember);
}
SalesPhoto Save Function --
private string saveImage(HttpPostedFileBase file, SalesMember salesmember, SalesMember SalesPhoto = null)
{
string photo = "";
string returnPhoto = "";
//File blank
if( file == null )
//If File Path For that User Already In DB, return that File Path
if(! String.IsNullOrEmpty(SalesPhoto.Photo))
return "/Images/no-upload-icon.jpg";
//If File ! empty, Save image uploaded
photo = Server.MapPath("/Images/" + salesmember.PageName.ToString() + ".jpg");
file.SaveAs(photo);
returnPhoto = "/Images/" + salesmember.PageName.ToString() + ".jpg";
return returnPhoto;
}
I believe it has to do with the LINQ Query, as when I remove the LINQ Query & saveImage method and just save the photo with a test path(i.e., "/Images/foo.jpg"), it works.
Thanks in advance.
You can not have two entities (same type) with same primary keys in memory in Entity Framework. salesmember and SalesPhoto if you want to have AddDate in your form Edit, you can Include it as a HiddenField in form, Or
my recommendation is to deal with ViewModels not EF models in views to
ignore these Issues
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="SalesMemberID,FirstName,LastName,PageName,CellPhone,Email,InactiveRedirectTo,CustomText,Photo,Active, Position")] SalesMember salesmember, HttpPostedFileBase file)
{
SalesMember SalesPhoto = db.SalesMembers.AsNoTracking().Find(salesmember.SalesMemberID);
salesmember.Photo = saveImage(file, salesmember, SalesPhoto);
if (ModelState.IsValid)
{
salesmember.AddDate = SalesPhoto.AddDate;
salesmember.UpdateDate = DateTime.Now;
salesmember.IPAddress = Request.UserHostAddress;
salesmember.AddUser = "admin";
salesmember.UpdateUser = "admin";
db.Entry(salesmember).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(salesmember);
}
I am having a problem in editing the role of a user. I have these codes:
`
Entities db2 = new Entities();
private UsersContext db = new UsersContext();
//
// POST: /AdminOnly/Edit/5
[Authorize(Roles = "Owner")]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(UserProfile userprofile, int? roless)
{
if (ModelState.IsValid)
{
webpages_UsersInRoles s = new webpages_UsersInRoles();
s = db2.webpages_UsersInRoles.Where(m => m.UserId == userprofile.UserId).FirstOrDefault();
if (s != null) //with existing role, edit it
{
s.RoleId = roless.Value;
db.Entry(userprofile).State = EntityState.Modified;
db2.Entry(s).State = EntityState.Modified;
db.SaveChanges();
db2.SaveChanges();
return RedirectToAction("Index");
}
else //no existing role
{
//some code here
}
}
ViewBag.roless = new SelectList(db2.webpages_Roles, "RoleId", "RoleName");
return View(userprofile);
}
`
When I try to save the changes in the database, db2.SaveChanges(); throws me an error that says:
An exception of type 'System.InvalidOperationException' occurred in
System.Data.Entity.dll but was not handled in user code
Additional information: The property 'RoleId' is part of the object's
key information and cannot be modified.
What should I do? Thanks in advance!
RoleId is used as key constraint and main identifier of entity. You can't change this id. Just don't update this property or add more comments why do you need to update it.
It's saying that RoleId is part of the primary key and cannot be changed. Instead of editing the existing row in webpages_UsersInRoles, try deleting that row and adding a new one with the new RoleId value.
Turns out that the column I want to change is a compound foreign key. I need to remove the first value of the RoleId and save the changes to the table. And add again the second value and save the new changes to the table. Thanks to those who helped!
One property has many photos. One photo belong to one property.
Inside my mvc controller I'm getting as parameter array of integers. These integers represents id of Photo which I want to delete.
I'm using nhibernate session and transaction to interact with db.
public ActionResult DeleteImgs(int[] data)
{
Property p = null;
using (ISession session = ....)
{
using(ITransaction transaction session.BeginTransaction())
{
Photo photo = session.Get<Photo>(data[0]);
p = session.Get<Property>(photo.Id);
// found images and delete them
foreach(int id in data)
{
Photo ph = session.Get<Photo>(id);
//remove property from association so I can delete photo
ph.Property = null;
session.Delete(ph);
session.SaveOrUpdate(ph);
}
//load property now with collection of remaining photos
// here IS THE PROBLEM, Even there is photos inside collection
// in debug I'm getting empty collection
p = session.Query<Property>().
.Fetch(x=>x.Photos).ToList() //empty?
.FirstOrDefault;
transaction.Commit();
}
}
return View();
}
Since I'm sending just IEnumrable of photos to the view problem is solved like this,
instead of sending lazy load property photos collection I'm sending IEnumerable of Photos like this
IEnumerable<Photo>photos = session.Query<Photo>().Where(x => x.Property == p).ToList();
So, here is my hopefully unique spin on this common problem.
I do my query, get my objects then pass the object into a form where it populates the form with the data from the object (this is not passed in by reference).
I then edit the values of the object that was queried (via the form) and then return a new object constructed from the values in the form.
I then want to update this to the database. Attach does nothing (runs but does not update). SubmitChanges also does nothing (and both do nothing when used together).
What am I missing?
Update: here is the code I am using:
// In constructor
_dataMap = new DataMapDataContext();
_addresses = _dataMap.AddressItems
.Where(address => address.InsertUserName == _currentUser.Name).ToList();
public void EditButtonClick()
{
using (AddAddressForm form = new AddAddressForm(_addresses[_currentAddress]))
{
form.Text = "Edit Address";
if (DialogResult.OK == form.ShowDialog())
{
_addresses[_currentAddress] = form.Item;
_dataMap.SubmitChanges();
DisplayItem();
}
}
}
You'll need to get the record from the database, update it's values and then call SubmitChanges()
using(MyDataContext db = new MyDataContext())
{
// get the record
Product dbProduct = db.Products.Single(p => p.ID == 1);
// set new values
dbProduct.Quantity = 5;
dbProduct.IsAvailable = false;
// save them back to the database
db.SubmitChanges();
}
Turns out I was doing almost everything right.
I just needed to pass in the object I was editing by reference. That way when it got changed, it was not a new object that was returned, but the same one (that Linq-to-SQL already knew about.)
These are the two lines from the code above that got changed:
AddressItem itemToEdit = _addresses[_currentAddress];
using (AddAddressForm form = new AddAddressForm(ref itemToEdit))