views:

108

answers:

2

In C# ASP.NET MVC application I use Link to SQL to provide data for my application. I have got simple database schema like this: My database

In my controller class I reference this data context called Model (as you can see on the right side of picture in properties) like this:

private Model model = new Model();

I've got a table (List) of Series rendered on my page. It renders properly and I was able to add delete functionality to delete Series like this:

public ActionResult Delete(int id) {
    model.Series.DeleteOnSubmit(model.Series.SingleOrDefault(s => s.ID == id));
    model.SubmitChanges();
    return RedirectToAction("Index");
}

Where appropriate action link looks like this:

<%: Html.ActionLink("Delete", "Delete", new { id=item.ID })%>

Also create (implemented in similar way) works fine. However edit does not work. My edit looks like this:

public ActionResult Edit(int id) {
    return View(model.Series.SingleOrDefault(s => s.ID == id));
}

[HttpPost]
public ActionResult Edit(Series series) {

    if (ModelState.IsValid) {
        UpdateModel(series);

        series.Title = series.Title + " some string to ensure title has changed";
        model.SubmitChanges();

        return RedirectToAction("Index");
    }
    return View(series);
}

I have controlled that my database has a primary key set up correctly. I debugged my application and found out that everything works as expected until the line with model.SubmitChanges();. This command does not apply the changes of Title property(or any other) against the database.

Please help.

EDIT: If I add this line: model.Series.Attach(series); just before model.SubmitChanges(); there is no change - edits still does not reflect to database. The instance passed to Edit method as a parameter is already attached to the data context model.

EDIT: Code of view that belongs to method Edit:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
Inherits="System.Web.Mvc.ViewPage<TVSeriesInfoApp.Models.Series>" %>

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<h2>Edit</h2>

<% using (Html.BeginForm()) {%>
    <%: Html.ValidationSummary(true) %>

    <fieldset>
        <legend>Fields</legend>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Title) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Title) %>
            <%: Html.ValidationMessageFor(model => model.Title) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Seasons) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Seasons) %>
            <%: Html.ValidationMessageFor(model => model.Seasons) %>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Stars) %>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Stars) %>
            <%: Html.ValidationMessageFor(model => model.Stars) %>
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>

<% } %>

<div>
    <%: Html.ActionLink("Back to List", "Index") %>
</div>

</asp:Content>
+1  A: 

First, never ever "delete" with HTTP GET (this is exactly what you're doing with Html.ActionLink("Delete", "Delete", new { id=item.ID }).

As for edits, you first have to Attach your instance to the DataContext.

Anton Gogolev
The instance is already attached to my data context. See edit.
drasto
As to "delete", the code `Html.ActionLink("Delete", "Delete", new { id=item.ID })` was generated by VS...
drasto
@Anton: Why not? He could be sending the request to another View and then have to confirm it via a HTTP POST.
Shaharyar
@Shaharyar: But he's not: there's a `Delete` method which is invoked via HTTP GET. Moreover, multiple POSTs just to delete an object will annoy the hell out of anybody.
Anton Gogolev
@drasto Then please show us full source, mainly for `UpdateModel` and whatever binders you have.
Anton Gogolev
@Anton: Oh totally overlooked that - in that case your answer is absolutely correct!
Shaharyar
+2  A: 

This is what our Edit Action would look like (Adjusted for your model):

[HttpPost]
public ActionResult Edit(int id, Series series)
{
    Series updatingSeries = model.Series.Single(s => s.ID == id);

    try
    {
        TryUpdateModel(updatingSeries);
        model.SubmitChanges();

        return RedirectToAction("Details", new { id = updatingSeries.ID });
    }
    catch
    {
        return View(updatingSeries);
    }
}

This can happen because the ModelState might not be valid in some cases. Have you done something to the View? Can you also post your View Code here please?

Shaharyar
The view works fine I guess because I have controlled content of series parameter returned to Edit method (using breakpoint). All properties are set as expected so the view works fine. Also I don't test it with invalid values yet, so the ModelState.isValid() is always true inside Edit method. No business rules are broken either. Ill add the view code anyway.
drasto
The view code is there - see last edit.
drasto
When I replace my code by yours it works.
drasto
Strange, your View looks good. Have you tried my approach? (It doesn't really do much more, just gets the item beforehand from the database and updates it..)
Shaharyar
Yes, I have already written your approach works. I don't know why, but I don't care I'm just happy that it works.
drasto