views:

17

answers:

1

I have a simple MVC 2 blog that I'm building as I learn. My edit page has title, body, date, enabled and tags. The tags is where my problem comes in. I have a Tags table and a Posts table and tags are associated to a post through the PostTag table. I have my linq model setup properly and I even have the Add HttpPost action working.

My problem is with the Edit view, where I want to remove tags that were on the Post object model at load time, and update them with the tags that are on the Post object model when it is HttpPost-ed. How can I accomplish this since my Model is complex? My Edit view:

[HttpPost, Authorize, ValidateInput(false)]
public ActionResult Edit(int id, FormCollection form)
{
    Post p = repo.GetPost(id);

    if (p == null)
        return View("NotFound");

    if (ModelState.IsValid)
    {
        try
        {
            UpdateModel(p);

            //Do something here to update the model p.TagList child model
            // the p.TagList object is not updated through UpdateModel

            repo.Save();

            return RedirectToAction("Post", "Blog", new { id = p.PostID });
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
            ModelState.AddRuleViolations(p.GetRuleViolations());
        }
    }
    return View(p);
}

What I've done to help translate tags on the Edit page to a collection of objects is through a TagListString object which just serializes each tag name separated by a space. When I post it back, I can easily reconstruct the TagList object by iterating through my TagListString - but it doesn't get updated!

I've tried several ways of updating the TagList model. Looping through and doing repo.Delete() on the existing ones and then adding then reconstructing and adding the new ones. I've tried just creating a new collection and adding the new Tag objects that way. Here are a few of the things I've tried.

public void UpdateTagList(System.Data.Linq.EntitySet<PostTag> postTags, string tagListString)
{
    db.PostTags.DeleteAllOnSubmit(postTags);
    db.PostTags.InsertAllOnSubmit(GenerateTagListFromString(tagListString, postTags.SingleOrDefault().Post));
}

private System.Data.Linq.EntitySet<PostTag> GenerateTagListFromString(string tagListString, Post post)
{
    System.Data.Linq.EntitySet<PostTag> tagList = new System.Data.Linq.EntitySet<PostTag>();

    foreach (var t in tagListString.Trim().Split(' '))
    {
        //look for this tag name in cache (MvcApplication.AllTags)
        Tag found = MvcApplication.AllTags.SingleOrDefault(item => item.TagName.Trim().ToLower() == t.Trim().ToLower());

        //new PostTag for this new Post
        PostTag pt = new PostTag();
        pt.Tag = found ?? new Tag() { TagName = t };
        pt.Post = post;

        tagList.Add(pt);
    }
    return tagList;
}
A: 

First of all, I'd recommend you to handle all form data with a custom ModelBinder, so your controller action receives a "Post" object with the updated scalar data and the right tags, instead of receiving FormCollection.

Then, the solution differs slightly depending if you're using .net 3.5 with EF 1.0 or .net 4.0 with EF 4.0.

Can you provide this information so I can help you further? Thanks.

Matteo Mosca
I had originally implemented my method to take a Post object but my child object wasn't getting passed in properly, is this because I didn't have a custom ModelBinder specifying how to bind that?I'm using .NET 3.5
MaseBase
I have created my custom ModelBinder, it was much easier than I thought, but now when I call repo.Save() it's not saving my object back to the DB. If I do repo.Add(p) before the save, then it does add it beautifully. But how do I inform the repository of my updated post? My repository class has no knowledge of what has changed for some reason.
MaseBase