Rawbert
Rawbert

Reputation: 581

Dynamic Data with Entity Framework: Bulk editing rows

I have a product admin web site that has been generated using ASP.NET Dynamic Data and Entity Framework 4.1 (Code First).

I've started creating a way of bulk editing rows. I have the edit controls for the columns I want to be able to bulk edit (I've created a new attribute called EditableInBulk that I decorate my properties with). I have also added a new column in the GridView with a checkbox that indicates if the row should be bulk edited or not.

The thing left now is I need to programmatically update the rows that I've checked with "Edit".

Here's the code that I use to find the rows that have been checked, the thing missing is to actually update the data and persist.

        // Find all items that will be edited
        foreach (GridViewRow row in GridView1.Rows)
        {
            if (row.RowType != DataControlRowType.DataRow)
                continue;

            // Fetch the item index of the rows that has "Edit" checked
            var editMe = row.Cells[1].Controls.OfType<CheckBox>().Any(ch => ch.Checked);
            if (editMe)
            {
                // Edit the fields in the row and persist
            }
        }

I should be able to use the UpdateRow method in the GridView control. But before that I need to update the fields within the row.

Does anyone have a clue on how I could achieve this?

The thing is also is that it needs to be generic. Should work with every entity type that has columns that I've decorated with my custom attribute "EditableInBulk". So there can't be any entity specific persisting going on.

I've started to modify the List.aspx file that comes with the Dynamic Data project.

Upvotes: 3

Views: 1613

Answers (1)

Rawbert
Rawbert

Reputation: 581

Ok we solved it.

I will explain the different parts to achieve a generic bulk edit for Dynamic Data with Entity Framework Code First. The solution isn't beautiful. But it works.

Create an attribute (we named it EditableInBulk) which you decorate the properties in your Entity Framework POCO class with.

In the List.aspx (autogenerated by Dynamic Data) add a column with a CheckBox control to your gridview so you easily can select which rows should be affected by the bulk update.

On ItemDataBound on the GridView, in the HeaderRow, add a DynamicControl of the correct type in the appropriate column. Only add the DynamicControl if the MetaColumn in question is decorated with EditableInBulk.

Create a button or somehow trigger the bulk update. First of all fetch the new values from the DynamicControl's that has been created in the HeaderRow.

Then iterate trough the GridView's rows (with RowType == DataRow). Make sure that current row has been selected as "to be edited" (find the CheckBox control in the new column and check the value).

Fetch the entity ID of current row. But first you must calculate the row number based on page and page size. Otherwise it won't work if you're on a page other than the first.

int index = row.DataItemIndex;
if (GridView1.PageIndex > 0)
{
    index = row.DataItemIndex - (GridView1.PageIndex)*GridView1.PageSize;
}
var entityId = Convert.ToInt32(GridView1.DataKeys[index].Value.ToString());

Instantiate an ObjectContext from your DataContext.

var objectContext = ((IObjectContextAdapter) new YourProject.Data.DataContext()).ObjectContext;

Fetch the entity type name of current list/dataset.

string entityTypeName = GridView1.DataKeyNames[0].Substring(0, GridView1.DataKeyNames[0].Count() - 2);

Instantiate a new object of type EntityKey with the help of the entity ID and entity type. Get the object that will be edited with the help of the ObjectContext

var entityKey = new EntityKey(objectContext.DefaultContainerName + "." + entityTypeName + "s", GridView1.DataKeyNames[0], entityId);

Note the + "s" solution... it works :) (happy/sad).

var entity = objectContext.GetObjectByKey(entityKey);

With the help of Reflection, set the new property values.

PropertyInfo prop = entity.GetType().BaseType.GetProperty(newValue.Key, BindingFlags.Public | BindingFlags.Instance);
var typedValue = TypeDescriptor.GetConverter(prop.PropertyType).ConvertFrom(newValue.Value);
                            if (null != prop && prop.CanWrite)
                            {
                                prop.SetValue(entity, typedValue, null);                            }

Save the newly updated entity!

objectContext.SaveChanges();

I assume there are several other better ways of achieving bulk update, but this works. If there's a demand for it, I will add more code from our solution. I just wanted to let you guys know that there is a way.

Upvotes: 4

Related Questions