ASP.NET MVC 2: Linq to SQL entity w/ ForeignKey relationship and Default ModelBinder strangeness
- by Simon
Once again I'm having trouble with Linq to Sql and the MVC Model Binder.
I have Linq to Sql generated classes, to illustrate them they look similar to this:
public class Client
{
public int ClientID { get; set; }
public string Name { get; set; }
}
public class Site
{
public int SiteID { get; set; }
public string Name { get; set; }
}
public class User
{
public int UserID { get; set; }
public string Name { get; set; }
public int? ClientID { get; set; }
public EntityRef<Client> Client { get; set; }
public int? SiteID { get; set; }
public EntityRef<Site> Site { get; set; }
}
The 'User' has a relationship with the 'Client' and 'Site
. The User class has nullable ClientIDs and SiteIDs because the admin users are not bound to a Client or Site.
Now I have a view where a user can edit a 'User' object, the view has fields for all the 'User' properties. When the form is submitted, the appropiate 'Save' action is called in my UserController:
public ActionResult Save(User user, FormCollection form)
{
//form['SiteID'] == 1
//user.SiteID == 1
//form['ClientID'] == 1
//user.ClientID == null
}
The problem here is that the ClientID is never set, it is always null, even though the value is in the FormCollection.
To figure out whats going wrong I set breakpoints for the ClientID and SiteID getters and setters in the Linq to Sql designer generated classes. I noticed the following:
SiteID is being set, then ClientID is being set, but then the Client EntityRef property is being set with a null value which in turn is setting the ClientID to null too! I don't know why and what is trying to set the Client property, because the Site property setter is never beeing called, only the Client setter is being called.
Manually setting the ClientID from the FormCollection like this:
user.ClientID = int.Parse(form["ClientID"].ToString());
throws a 'ForeignKeyReferenceAlreadyHasValueException', because it was already set to null before. The only workaround I have found is to extend the generated partial User class with a custom method:
Client = default(EntityRef<Client>)
but this is not a satisfying solution. I don't think it should work like this?
Please enlighten me someone. So far Linq to Sql is driving me crazy!
Best regards