passing mulitple rows from view to controller

passing mulitple rows from view to controller

Postby akash.hegde@gmail.com » Tue 03 Jan 2012 01:15

Hi
I'm using dotconnect for postgrsql with entity framework. I have a view that displays multiple rows from a table. The view loops through the model and displays rows as below...

@model IEnumerable<IntegratorModel.ServiceOrderAttribute>

@{
ViewBag.Title = "Index";
}

<h2>Index</h2>


@Html.ActionLink("Update rows", "Edit")

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend>ServiceOrderAttribute</legend>

@foreach (var item in Model)
{

<div class="editor-label">
@Html.LabelFor(model => item.AttributeName)
</div>
<div class="editor-field">
@Html.EditorFor(model => item.AttributeName)
@Html.ValidationMessageFor(model => item.AttributeName)
</div>

<div class="editor-label">
@Html.LabelFor(model => item.AttributeValue)
</div>
<div class="editor-field">
@Html.EditorFor(model => item.AttributeValue)
@Html.ValidationMessageFor(model => item.AttributeValue)
</div>
}


<input type="submit" value="Edit" />

</fieldset>
}

The user can update the AttributeValue for each row on the form.

How do i pass the multiple rows updated to the controller and have them update the database table. My controller is below (as you can see it can handle just one row)


[HttpPost]
public ActionResult Edit(ServiceOrderAttribute serviceorderattribute)
{
if (ModelState.IsValid)
{
db.ServiceOrderAttributes.Attach(serviceorderattribute);
db.ObjectStateManager.ChangeObjectState(serviceorderattribute, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index");
}

return View(serviceorderattribute);
}

Update:
I also tried passing in IEnumerable (using html form collection) to the controller, however on submitting it throws an error

[InvalidOperationException: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.]
System.Data.Objects.ObjectContext.VerifyRootForAdd(Boolean doAttach, String entitySetName, IEntityWrapper wrappedEntity, EntityEntry existingEntry, EntitySet& entitySet, Boolean& isNoOperation) +8595812
System.Data.Objects.ObjectContext.AttachTo(String entitySetName, Object entity) +194
System.Data.Objects.ObjectSet`1.Attach(TEntity entity) +29
Code in controller:

[HttpPost]
public ActionResult Edit(IEnumerable<ServiceOrderAttribute> serviceOrderAttribute)
{
foreach (var item in serviceOrderAttribute)
{

if (ModelState.IsValid)
{
db.ServiceOrderAttributes.Attach(item);
db.ObjectStateManager.ChangeObjectState(item, EntityState.Modified);
db.SaveChanges();
// return RedirectToAction("Index");
}
}
return View();
}

Code in view:

@foreach (var item in Model)
{
using (Html.BeginCollectionItem("ServiceOrderAttribute"))
{
Html.HiddenFor(model => item.Id);
Html.HiddenFor(model => item.ServiceOrderId);


<div class="editor-label">
@Html.LabelFor(model =>item.AttributeName)
</div>
<div class="editor-field">
@Html.EditorFor(model => item.AttributeName)
@Html.ValidationMessageFor(model => item.AttributeName)
</div>

<div class="editor-label">
@Html.LabelFor(model => item.AttributeValue)
</div>
<div class="editor-field">
@Html.EditorFor(model => item.AttributeValue)
@Html.ValidationMessageFor(model => item.AttributeValue)
</div>
}




Thanks in advance
akash.hegde@gmail.com
 
Posts: 15
Joined: Sat 26 Nov 2011 00:56

Postby Shalex » Wed 11 Jan 2012 15:52

As we understood, you are getting a collection of entities (POCO, perhaps), updating some of them, and trying to attach them (as modified) to the ObjectContext instance.

1. If this is the same ObjectContext (the one you obtained the original objects from), there is no need to attach them because they are already loaded to ObjectStateManager, and their states are tracked.

2. If these are different instances of ObjectContext, there can be possible problems with incorrect set of EntityKeys.
View doesn't have a primary key. So Entity Key is set by EF runtime dynamically. You can encounter the following situation: the Entity Key of all your entities is the same (this particular column of view in the database has the same value for all records), so only the first record is retrieved from the database during reading, and its entity is attached to the context, and this entity will be re-added to the context each iteration because its Entity Key coincides with the newly created Entity Key of the next entity.
As a solution, set the EntityKey attribute to true for the set of properties in your entity to identify uniquely every record in your view.
Shalex
Devart Team
 
Posts: 5885
Joined: Thu 14 Aug 2008 12:44

Postby akash.hegde@gmail.com » Thu 12 Jan 2012 00:59

Each row in the view has a primary key though ....so the update should be using the entity key to update affected rows.

If you look at my view code (in the original post)

Html.HiddenFor(model => item.Id);

item.id is the id column which is a primary key on the table. So entity keys are unique for every row.
akash.hegde@gmail.com
 
Posts: 15
Joined: Sat 26 Nov 2011 00:56

Postby Shalex » Thu 12 Jan 2012 15:10

akash.hegde@gmail.com wrote:[InvalidOperationException: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.]
...
System.Data.Objects.ObjectSet`1.Attach(TEntity entity) +29

There are two possible scenarios:
1. You are re-attaching the entity to the same ObjectContext. We have already mentioned about this case:
Shalex wrote:If this is the same ObjectContext (the one you obtained the original objects from), there is no need to attach them because they are already loaded to ObjectStateManager, and their states are tracked.

2. You are attaching the entity to the different ObjectContext which already has an entity with the same key.

If this doesn't help, please localize the issue and send us a small test project with the corresponding DDL/DML script to reproduce the issue in our environment.
Shalex
Devart Team
 
Posts: 5885
Joined: Thu 14 Aug 2008 12:44

Postby akash.hegde@gmail.com » Fri 13 Jan 2012 10:53

I'm not sure i understand what you mean by "If this is the same ObjectContext (the one you obtained the original objects from), there is no need to attach them because they are already loaded to ObjectStateManager, and their states are tracked."

so if there are 5 rows displayed on the page and I update 2 rows, all 5 rows are passed to the controller regardless if only 2 rows have changed data.

Are you saying that the statement below is not needed if a row's data has not changed?

db.ServiceOrderAttributes.Attach(serviceorderattribute);
akash.hegde@gmail.com
 
Posts: 15
Joined: Sat 26 Nov 2011 00:56

emailed test project

Postby akash.hegde@gmail.com » Sun 15 Jan 2012 05:24

Hi
I have emailed a small project top you for this including dml / ddl scripts

Thanks
akash.hegde@gmail.com
 
Posts: 15
Joined: Sat 26 Nov 2011 00:56

Postby Shalex » Thu 19 Jan 2012 13:09

The test project you have sent to us doesn't work. Please send us a working one (which reproduces the issue). Here are some articles about using Entity Framework with MVC:
http://www.codeproject.com/KB/aspnet/ASP_NET_MVC_WITH_EF.aspx
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc
Shalex
Devart Team
 
Posts: 5885
Joined: Thu 14 Aug 2008 12:44


Return to dotConnect for PostgreSQL