Cameron
Cameron

Reputation: 28853

ASP.NET MVC Sequence contains no elements

I have the following code in my HomeController:

    public ActionResult Edit(int id)
    {
        var ArticleToEdit = (from m in _db.ArticleSet where m.storyId == id select m).First();
        return View(ArticleToEdit);
    }

    [ValidateInput(false)]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(Article ArticleToEdit)
    {

        var originalArticle = (from m in _db.ArticleSet where m.storyId == ArticleToEdit.storyId select m).First();
        if (!ModelState.IsValid)
            return View(originalArticle);

        _db.ApplyPropertyChanges(originalArticle.EntityKey.EntitySetName, ArticleToEdit);
        _db.SaveChanges();
        return RedirectToAction("Index");

    }

And this is the view for the Edit method:

<% using (Html.BeginForm()) {%>

    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="headline">Headline</label>
            <%= Html.TextBox("headline") %>
        </p>
        <p>
            <label for="story">Story <span>( HTML Allowed )</span></label>
            <%= Html.TextArea("story") %>
        </p>
        <p>
            <label for="image">Image URL</label>
            <%= Html.TextBox("image") %>
        </p>
        <p>
            <input type="submit" value="Post" />
        </p>
    </fieldset>

<% } %>

When I hit the submit button I get the error: Sequence contains no elements on this line: var originalArticle = (from m in _db.ArticleSet where m.storyId == ArticleToEdit.storyId select m).First();

What is the problem? How do I fix it. Thanks

Upvotes: 1

Views: 11682

Answers (3)

Chase Florell
Chase Florell

Reputation: 47417

You need to be sure of is that when you're editing a record, you need to tell the database what record to edit. It's not enough to have the ID in the querystring unless you specifically tell the Model to use that ID (see my second option), however the easiest way to do that is add the field in your form.

<% using (Html.BeginForm()) {%>
<%= Html.HiddenFor("storyId") %>
    <fieldset>
        <legend>Fields</legend>
        <p>
            <label for="headline">Headline</label>
            <%= Html.TextBox("headline") %>
        </p>
        <p>
            <label for="story">Story <span>( HTML Allowed )</span></label>
            <%= Html.TextArea("story") %>
        </p>
        <p>
            <label for="image">Image URL</label>
            <%= Html.TextBox("image") %>
        </p>
        <p>
            <input type="submit" value="Post" />
        </p>
    </fieldset>

<% } %>

This second option shows how to specify the storyId after the fact by submitting it to the Action via the Querystring. You just have to make sure the form action includes ?storyId=[n]

[ValidateInput(false)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Article ArticleToEdit, int storyId)
{

    ArticleToEdit.storyId = storyId;

    if (ModelState.IsValid) {
        _db.ApplyPropertyChanges(originalArticle.EntityKey.EntitySetName, ArticleToEdit);
        _db.SaveChanges();
        return RedirectToAction("Index");

    } else {
        return View(ArticleToEdit);
    }
}

I would also suggest using something like AutoMapper to map ArticleToEdit to ArticleSet so that you don't need to make an additional DB lookup just to grab the original article. Basically if you are able to map ArticleToEdit to the ArticleSet Model, then you can use LINQ to SQL to perform the update without first querying for the storyId.

Upvotes: 1

sgriffinusa
sgriffinusa

Reputation: 4221

You are not including the ID of the article in your HTML form. If you debug the ArticleToEdit object is probably either null or has zero storyId.

You should include your storyId in the HTML form. You can do it as a hidden field if you don't want the user to see it. For example:

<% using (Html.BeginForm()) {%>
    <%= Html.HiddenFor("storyId") %>
    ...

On a separate note, you should probably switch to using Single instead of First. First indicates that you want the First item in a collection. Single indicates that you should get one and only one result.

Upvotes: 3

John Farrell
John Farrell

Reputation: 24754

The problem is you have nothing that matches your linq query in _db.ArticleSet. First will throw against an empty collection.

Try FirstOrDefault() if returning null is ok. FirstOrDetault() will return null if nothing matches.

Upvotes: 3

Related Questions