views:

431

answers:

3

Hi all,

Is there a pre-built ModelBinder I can use with LINQ to get an object from a DataContext and update it on a HTTP post?

For example, currently I have this block of code:

[AcceptVerbs (HttpVerbs.Post)]
public ActionResult Edit (Project project)
{
    var projectService = Factory.GetService<IProjectService> ();
    project = projectService.GetProject (project.ProjectId);

    UpdateModel<Project> (project);

    if (!ModelState.IsValid)
     return View (project);

    project = projectService.SaveProject (project);

    return RedirectToAction ("Details", new { id = project.ProjectId });
}

(IProjectService wraps up calls to a LINQ data context)

In order to actually perform the update to the database via the LINQ data context, I need to get the project instance again and then update that instance.

Any attempt to simply save the project instance without first getting it from the data context results in nothing being written back to the database - I'm assuming because the LINQ data context knows nothing of the object it doesn't do anything with it.

Using the Attach method on the Projects table class doesn't work either btw, it throws an exception.

A: 

I think the project you pass in to the method is the one you want to perform UpdateModel with isn't it?

Otherwise you are trying to update with pre-existing values not new ones.

Just a thought,

Dan

Code cut out below

[AcceptVerbs (HttpVerbs.Post)]
public ActionResult Edit (Project project)

    UpdateModel<Project> (project);

    if (!ModelState.IsValid)
            return View (project);

    var projectService = Factory.GetService<IProjectService> ();

    project = projectService.SaveProject (project);

    return RedirectToAction ("Details", new { id = project.ProjectId });
}
Daniel Elliott
project and not projectToUpdate is the one using the ModelBinder
Daniel Elliott
The problem, which I not explaining very well, is that the project instance that comes from the binder is all well and good, apart from the fact it was constructed by the MVC FW somewhere down the line, and not retrieved from the DataContext. When updating that instance, the DataContext basically does nothing, probably because it knows nothing of that object.
Kieron
A: 

You need to retrieve the original project as you do then to update it with the properties that have changed in project to update then to submit the update request.

EDIT

Try this code I found:

public static void CloneProperties(this object origin, ref object destination)
{ 
    if (destination == null) throw new ArgumentNullException("destination", "Destination object must first be instantiated."); 
    foreach (var destinationProperty in destination.GetType().GetProperties()) 
    {
       if (origin != null && destinationProperty.CanWrite) 
       { 
          origin.GetType().GetProperties().Where(x => x.CanRead && (x.Name == destinationProperty.Name && x.PropertyType == destinationProperty.PropertyType)) .ToList() .ForEach(x => destinationProperty.SetValue(destination, x.GetValue(origin, null), null)); 
       } 
    } 
}
Gregoire
Yeah, that's what I'm doing - what I'd like is to maybe create a ModelBinder that would do that for me...simply so I don't have to do a get in the controllers every time.If I change to another ORM later, I'll be doing extra gets that aren't required. All I'd need to do with the binder is remove/ restore the original. Any thoughts?
Kieron
http://msdn.microsoft.com/en-us/library/bb896248.aspx
Gregoire
@Gregorie, I tried using the Attach method a while back, but it throws an exception about the object already exists (I assume it's checking based on it's PK).
Kieron
That's what the UpdateModel method will do with the freshly retrieved projectToUpdate instance.
Kieron
+3  A: 

You should look at the implementation in Mike Hadlow's (new BSD) SutekiShop.

In there you will find a DataBindAttribute and BindUsingAttribute which, if I understand correctly, do exactly what you want to do. Notice how the DataBindAttribute.Fetch property is used to rebind the incoming data, or not, (from an HttpPost) to a LINQ entity.

I followed this pattern for one of my projects using ASP.NET MVC and LINQ-To-SQL. It works beautifully.

Here's the source: http://www.google.com/codesearch?hl=en&amp;lr=&amp;q=DataBind+package%3Ahttp%3A%2F%2Fsutekishop.googlecode.com&amp;sbtn=Search

Robert Claypool
That's it exactly, thanks Robert!
Kieron
SutekiShop has a lot of great code, glad it is working for you.
Robert Claypool