views:

1606

answers:

2

To get my head round some fundamentals using MVC and Linq to SQL I'm working on an adaption to Stephen Walther's TaskList application:

I'm adding a Bulk Edit system using the concepts described in Steve Sanderson's blog.

This all works as expected, however, I'm having trouble saving my returned List of Tasks. The Post to my BulkEdit loops through the returned list and updates each item in my LinqToSql db list of Tasks.

My BulkEdit view inherits ViewPage<List<TaskList.Models.Task>> and is as follows:

<% 
using (Html.BeginForm())
{
%>
        <div id="items">

<%
            foreach (var task in ViewData.Model)
            {
                Html.RenderPartial(
                    "TaskEditor",
                    task,
                    new ViewDataDictionary(ViewData)
                            {
                                {"prefix", "tasks"}
                            }
                );
            }
%>

        </div>

        <input type="submit" value="Save changes" />

<%
    }
%>

The TaskEditor control inherits System.Web.Mvc.ViewUserControl<Models.Task> and looks like this:

<div>
<%= Html.Hidden(ViewData["prefix"] + ".index", ViewData.Model.Id) %>

<% var fieldPrefix = string.Format("{0}[{1}].", ViewData["prefix"], ViewData.Model.Id); %>

<%= Html.Hidden(fieldPrefix + "Id", ViewData.Model.Id) %>
Description:
<%= Html.TextBox(fieldPrefix + "TaskDescription", ViewData.Model.TaskDescription)%>
Date:
<%= Html.TextBox(fieldPrefix + "EntryDate", ViewData.Model.EntryDate.ToString("o"))%>   
Completed:
<%= Html.CheckBox(fieldPrefix + "IsCompleted", ViewData.Model.IsCompleted)%>
</div>

The Controller Get and Post methods are as follows:

    [AcceptVerbs(HttpVerbs.Get)]
    public ActionResult BulkEdit()
    {
        var tasks = from t in db.Tasks orderby t.EntryDate descending select t;

        return View(tasks.ToList());
    }        

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult BulkEdit(IList<Task> tasks)
    {
        foreach(Task task in tasks)
        {
            foreach(Task dbTask in db.Tasks)
            {
                if (dbTask.Id == task.Id)
                {
                    dbTask.TaskDescription = task.TaskDescription;
                    dbTask.EntryDate = task.EntryDate;
                    dbTask.IsCompleted = task.IsCompleted;
                }
            }
        }

        db.SubmitChanges();

        return RedirectToAction("Index");
    }

My question is, this seems too complicated and I haven't yet accounted for tasks being added or deleted from the list. What I would prefer to do is something like

db.Tasks = tasks;

and let Linq do all its magic to work out which ones have changed and which ones are new / old.

Is this possible? Or am I expecting a bit too much from Linq so soon?

A: 

Hi, I think you should consider using a view to accompish what you want. the ObservebleCollection collection to hold the items and then you can have a binding in your list to the view of that collection, you would still need to handle cases of adding and deleing of items, but you can also opt of an IBindingList which will give you a BindingListCollectionView that will update the DB, all you need to do is call the views AddNew() CommitNew() and so on.

HTH, Eric

+1  A: 

You're dealing with the fact that LINQ to SQL has no multi-tier story. I think that this is what you're looking for:

http://blog.irm.se/blogs/eric/archive/2008/08/20/Go-Distributed-With-LINQ-to-SQL.aspx

The Merge method that this guy presents could be easily turned into an "extension method" of the DataContext class and it would almost be just like it was built right into LINQ to SQL. I say almost because you'd have to include the namespace of where your extension method is located in order to use it.

wizlb