Im learning MVC 4. I have created a database first project using EF5. In my edit view I want to add a product number to a customer. When I hit save I get the message below. I think it is because product number is null in the product table, hence it cannot update. Can I get around this? I have added my edit control
public ActionResult Edit(int id = 0)
{
UserProfile userprofile = db.UserProfiles.Find(id);
if (userprofile == null)
{
return HttpNotFound();
}
//ViewBag.userId = new SelectList(db.Devices, "DeviceID", "DeviceIMEI", userprofile.UserId);THIS CREATES A NEW ENTRY IN USERPROFILE TABLE
ViewBag.Device_DeviceID = new SelectList(db.Devices, "DeviceID", "DeviceIMEI", userprofile.Device);
ViewBag.ShippingDetails_ShippingDetailsID = new SelectList(db.ShippingDetails, "ShippingDetailsID", "Address1", userprofile.ShippingDetails_ShippingDetailsID);
return View(userprofile);
}
//
// POST: /User/Edit/5
[HttpPost]
public ActionResult Edit(UserProfile userprofile)
{
if (ModelState.IsValid)
{
db.Entry(userprofile).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
//ViewBag.userId = new SelectList(db.Devices, "DeviceID", "DeviceIMEI", userprofile.UserId);
ViewBag.Device_DeviceID = new SelectList(db.Devices, "DeviceID", "DeviceIMEI", userprofile.Device);
ViewBag.ShippingDetails_ShippingDetailsID = new SelectList(db.ShippingDetails, "ShippingDetailsID", "Address1", userprofile.ShippingDetails_ShippingDetailsID);
return View(userprofile);
}
"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"
It looks like you dont pass Id of UserProfile from
view to controller.
You should add
#Html.HiddenFor(model => model.Id)
to your form in view
You're posting a view model, which is disconnected from your entity framework, and trying to tell the EF that it has changed -- which it doesn't know about. Try something like this instead,
var obj = yourContext.UserProfiles.Single(q=>q.Id==userProfile.Id);
obj = userprofile; // ... Map userprofile to the tracked object, obj
yourContext.SaveChanges();
Try this:
if (ModelState.IsValid)
{
db.UserProfiles.Attach(userProfile);
db.SaveChanges();
return RedirectToAction("Index");
}
Related
I have following code. in that i am trying to update my data. but i am getting error message:
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code
Additional information: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
Here is my code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="CompanyId,Address,EstbalishYear,Email,IsActive")] CompanyMaster companymaster)
{
if (companymaster.CompanyId == 0)
{
return View(companymaster);
}
CompanyMaster company = db.CompanyMasters.SingleOrDefault(x => x.CompanyId == companymaster.CompanyId);
companymaster.Name = company.Name;
companymaster.InsertedBy = company.InsertedBy;
companymaster.InsertedTime = company.InsertedTime;
companymaster.UpdatedBy = 1;
companymaster.UpdatedTime = DateTime.Now;
ModelState.Remove("Name");
if (ModelState.IsValid)
{
db.Entry(companymaster).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(companymaster);
}
Please explain me how can I fix this error message?
This is because you are working with two object instances of a company master, which in reality is a single entity, with the same ID.
One (companyMaster) comes as an argument to the Edit method, via binding.
The other one (company) you are selecting from the database through db.CompanyMasters by ID
What you can do is
Select company by ID, as you do now
Set company properties from companyMaster object (vice-versa, not like you do now)
Save the company object
Please find the sample code below.
Please also note that the best practice is not to use your persistence entity model in UI layer, but rather define a DTO with a minimum set of required fields, and then map it to your entity either manually or using AutoMapper.
[HttpPost] [ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="CompanyId,Address,EstbalishYear,Email,IsActive")] CompanyMaster companymaster)
{
if (companymaster.CompanyId == 0)
{
return View(companymaster);
}
CompanyMaster company = db.CompanyMasters.SingleOrDefault(x => x.CompanyId == companymaster.CompanyId);
company.Address = companymaster.Address;
company.EstbalishYear= companymaster.EstbalishYear;
company.Email = companymaster.Email;
company.IsActive= companymaster.IsActive;
company.UpdatedBy = 1;
company.UpdatedTime = DateTime.Now;
ModelState.Remove("Name");
if (ModelState.IsValid)
{
db.SaveChanges();
return RedirectToAction("Index");
}
return View(companymaster);
}
I have 2 tables tbl_computer and tbl_computerperipheral
I need a editor view which consists of data from both tables.
How Can I get 2 tables in a single view so that I can insert data into 2 tables at once.
Thanx
For your Better Reference just have a look to ::
How to Combine two models into a single model and pass it to view using asp.net MVC razor
and then on Form submit on server side (i.e. into controller's action) save the data coming from view in the form like::
public ActionResult Save(CommonViewModel common)
{
var FirstModel = new FirstModel();
FirstModel = common.FirstModel;
db.Entry(FirstModel).State = EntityState.Added;
var SecondModel = new SecondModel();
SecondModel = common.SecondModel;
db.Entry(SecondModel).State = EntityState.Added;
db.SaveChanges();
}
May be this answer will be helpful to get answer of your Query.
[HttpPost]
public ActionResult Edit(CompPeripheral cp, int c_id,int em_id,int asset_id)
{
if (ModelState.IsValid)
{
cp.Compconfig.c_id = c_id;
cp.Compconfig.em_id = em_id;
cp.Compconfig.asset_id = asset_id;
db.tbl_compconfig.Add(cp.Compconfig);
db.SaveChanges();
var id = db.tbl_compconfig.Max(a => a.comp_id);
cp.Comperipheral.comp_id = id;
//saving Comp Peripheral in database
db.tbl_comperipheral.Add(cp.Comperipheral);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.asset_id = new SelectList(db.tbl_assetm, "asset_id", "asset_name", cp.Compconfig.asset_id);
ViewBag.em_id = new SelectList(db.tbl_employee, "em_id", "em_fullname", cp.Compconfig.em_id);
ViewBag.c_id = new SelectList(db.tbl_client, "c_id", "c_name", cp.Compconfig.c_id);
return View(cp);
}
The foreach does not delete anything.. it only seems to NULL some fields in the table.. .. and how I delete the main parent after that Im not sure... been looking around for a simple solution with no luck..
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
tMember mem = db.tMembers.Find(id);
// find all VoteScores related to the member and delete them
var voteScores = db.tMemVoteScores.Where(mvs => mvs.MembersID == mem.MembersID).AsEnumerable();
foreach (var mvs in voteScores)
{
var singleMvs = mvs;
mem.tMemVoteScores.Remove(singleMvs);
}
db.SaveChanges();
//Delete the actual member now... where is the remove method?
// mem.remove???
return RedirectToAction("Index");
}
Remove calls in Entity Framework need to be done at the DbSet level, and not on the individual items found in a list. This would also need to be done for the parent object itself, i.e. the following:
foreach (var mvs in voteScores)
{
var singleMvs = mvs;
db.tMemVoteScores.Remove(singleMvs);
}
db.tMembers.Remove(mem);
db.SaveChanges();
tMember mem = db.tMembers.Find(id);
db.Entry(mem).State = EntityState.Deleted;
db.SaveChanges();
How about this?
I've look at some of the answers to similar questions and they don't really seem to fit mine.
I'm trying to incorporate a pattern from Entity Framework: DbContext(page 90) and it doesn't seem to work. The code that I'm using is given below:
[HttpPost]
public ActionResult Edit(Order order)
{
if (ModelState.IsValid)
{
db.Orders.Add(order);
db.Entry(order).State = EntityState.Modified;
foreach (var orderDetail in order.OrderDetails)
{
if (orderDetail.OrderId == 0)
{
db.Entry(orderDetail).State = EntityState.Added;
}
else
{
db.Entry(orderDetail).State = EntityState.Modified;
}
// The example order that I'm updating has two child entities
// so this orderId will be for the third, added one.
int addedOrderDetailId = order.OrderDetails[2].OrderId;
}
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "CompanyName", order.CustomerId);
return View(order);
}
I've been running an example where the Order object has two existing OrderDetail objects and I'm attempting to add a third. I included the addedOrderDetailId variable, so that I could add it to the 'Watch' and see when it changed
What I've found is happening is that the OrderId of the added OrderDetail object (which is 0 when the foreach loop is entered) is being updated by entity framework to the OrderId of the Order object. This is happening at after the first iteration through the foreach loop (when the first child entity is having its state changed to modified. This means that all three children are being marked as modified. This is causing SaveChanges() to try to update an entry into the database that doesn't exist.
If anyone else has had this problem, then I would be greatful for any advice as to get around this. I will also have to deal with existing child objects being deleted, but I haven't got around to this yet, so if anyone knows of a pattern for this, that would also be appreciated.
Edit:
After taking Slauma's advice and removing db.Orders.Add(order). I was able to move the call to db.Entry(order).State underneath the foreach loop. This allowed me to loop through the loop and set the state of each OrderDetail object to modified for the existing ones and added for the added one. I then simply had to assign the OrderId of the parent to the OrderId of the child and the update was successful. I've also included the code that I've used to delete child objects during the edit. I'm not sure how efficient this is, but it works. Here is the revised code:
[HttpPost]
public ActionResult Edit(Order order)
{
if (ModelState.IsValid)
{
List<int> previousProductIds = db.OrderDetails
.Where(ep => ep.OrderId == order.OrderId)
.Select(ep => ep.ProductId)
.ToList();
List<int> currentProductIds = order.OrderDetails
.Select(o => o.ProductId)
.ToList();
List<int> deletedProductIds = previousProductIds
.Except(currentProductIds).ToList();
foreach (var deletedProductId in deletedProductIds)
{
OrderDetail deletedOrderDetail = db.OrderDetails
.Where(od => od.OrderId == order.OrderId && od.ProductId == deletedProductId)
.Single();
db.Entry(deletedOrderDetail).State = EntityState.Deleted;
}
foreach (var orderDetail in order.OrderDetails)
{
if (orderDetail.OrderId == 0)
{
db.Entry(orderDetail).State = EntityState.Added;
orderDetail.OrderId = order.OrderId;
}
else
{
db.Entry(orderDetail).State = EntityState.Modified;
}
}
db.Entry(order).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CustomerId = new SelectList(db.Customers, "CustomerId", "CompanyName", order.CustomerId);
return View(order);
}
Remove this line from your code:
db.Orders.Add(order);
This will actually put the order including all orderDetails into Added state. Relationship fixup (which happens automatically in Add) will set the OrderId of all OrderDetails to the key of the order. When you enter the loop orderDetail.OrderId is != 0 for all detail items and you always enter the branch which sets the state to Modified. No orderDetail item is in Added state anymore when the loop is finished.
I'm using the latest Asp.Net MVC version.
For some reason, when my POST (Action Create) in my controller gets hit.
I can't seem to be able to add it to the entityset.
What i have is,
1) My EntityModel (*.edmx file)
2) Controller which references the entity:
private db.DataContainer _db = new db.DataContainer();
3) My method (i'm using Guid as pk):
[HttpPost]
public ActionResult Create(Client client)
{
try
{
client.Id = Guid.NewGuid();
/* method 2
Client cl = new Client();
cl.Id = Guid.NewGuid();
cl.email = client.email;
cl.Adres = client.Adres;
cl.companyName = client.companyName;
cl.fax = client.fax;
cl.phone = client.phone;
*/
// client.Id = Guid.NewGuid();
_db.ClientSet.AddObject(client);
_db.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
var ex_message = ex.Message;
var ex_data = ex.Data;
var ex_ix = ex.InnerException;
return View();
}
}
4) Following is my InnerException:
[System.Data.SqlClient.SqlException] = {"Cannot insert the value NULL into column 'Id', table 'lst.dbo.ClientSet'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}
Both doesn't seem to work :(
GUIDs are not supported as primary keys in the Entity Framework. You will need to modify your save method to generate a new GUID for your added objects http://msdn.microsoft.com/en-us/library/dd283139.aspx
It seems that changing my "saveCommand" has given my a temporarily solution:
I chaned:
_db.SaveChanges()
To
_db.SaveChanges(System.Data.Objects.SaveOptions.None);