views:

392

answers:

1

I have a Linq to Sql Entity which has an EntitySet. In my View I display the Entity with it's properties plus an editable list for the child entites. The user can dynamically add and delete those child entities. The DefaultModelBinder works fine so far, it correctly binds the child entites.

Now my problem is that I just can't get Linq To Sql to delete the deleted child entities, it will happily add new ones but not delete the deleted ones. I have enabled cascade deleting in the foreign key relationship, and the Linq To Sql designer added the "DeleteOnNull=true" attribute to the foreign key relationships. If I manually delete a child entity like this:

myObject.Childs.Remove(child);
context.SubmitChanges();

This will delete the child record from the DB. But I can't get it to work for a model binded object. I tried the following:

// this does nothing
public ActionResult Update(int id, MyObject obj) // obj now has 4 child entities
{
    var obj2 = _repository.GetObj(id); // obj2 has 6 child entities
    if(TryUpdateModel(obj2)) //it sucessfully updates obj2 and its childs
    {
         _repository.SubmitChanges(); // nothing happens, records stay in DB
    }
    else
         .....

    return RedirectToAction("List");
}

and this throws an InvalidOperationException, I have a german OS so I'm not exactly sure what the error message is in english, but it says something along the lines of that the entity needs a Version (Timestamp row?) or no update check policies. I have set UpdateCheck="Never" to every column except the primary key column.

public ActionResult Update(MyObject obj)
{
    _repository.MyObjectTable.Attach(obj, true);
    _repository.SubmitChanges(); // never gets here, exception at attach
}

I've read alot about similar "problems" with Linq To Sql, but it seems most of those "problems" are actually by design. So am I right in my assumption that this doesn't work like I expect it to work? Do I really have to manually iterate through the child entities and delete, update and insert them manually? For such a simple object this may work, but I plan to create more complex objects with nested EntitySets and so on. This is just a test to see what works and what not. So far I'm disappointed with Linq To Sql (maybe I just don't get it). Would be the Entity Framework or NHibernate a better choice for this scenario? Or would I run into the same problem?

A: 

It will definately work in Entity Framework that comes with .NET 4 (I'm doing similar things in the RC version)

This does not explain the exception but:

You should dispose the ObjectContext that's (most likely) wrapped in your repository. The context caches items, and should only be used for a single unit-of-work.

Try to use a pattern like:

public ActionResult Update(int id, MyObject obj) // obj now has 4 child entities
{
    using(var repository = CreateRepository())
    {
        var obj2 = _repository.GetObj(id);
        if(TryUpdateModel(obj2))
        {
             repository.SubmitChanges();
        }
        else
            .....
    }

    return RedirectToAction("List");
}

When fetching items, create a new repository as well. They are cheap to create and dispose, and should be disposed as quickly as possible.

Sander Rijken
Currently I'm creating the repository in the constructor of the Controller, so I expect it to live for a single request only, or am I wrong? Does a controller live longer? (I'm just getting started with MVC and LinqToSql)I tried it with the using statement inside the action, but strangely enough it keeps adding new records for the child objects. I'll keep investigating. Thanks so far!
Simon
Good point there, add some breakpoints: Where the repository is created, in the `.Update` and in `.List`. If the constructor isn't executed twice, you have a possible problem.
Sander Rijken
Ok I just checked this and the repository is being created for each request
Simon