C# – Why won’t SubSonic ActiveRecord update the data

asp.net-mvccsubsonicsubsonic3

I am playing around with SubSonic 3 ActiveRecord. I have a table called Users and I have the following fields in a MySQL database:

CREATE TABLE `users` (
  `ID` int(10) NOT NULL auto_increment,
  `Username` varchar(50) NOT NULL,
  `FirstName` varchar(50) default NULL,
  `LastName` varchar(50) default NULL,
  `EmailAddress` varchar(100) default NULL,
  `OfficePhone` varchar(25) default NULL,
  `MobilePhone` varchar(25) default NULL,
  `TimeZone` varchar(25) default NULL,
  `LastLogin` datetime default NULL,
  PRIMARY KEY  (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1  

I can read from the table with no problems. I can add new records with no problems but I can not update existing records for some reason. I have stepped through the code and the editUser object has the correct data in it.

[AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(FormCollection result)
    {
        var editUser = ServiceDesk.Data.User.SingleOrDefault(x => x.ID == Convert.ToInt32(result["ID"]));
        UpdateModel(editUser);
        editUser.Save();
        return RedirectToAction("Index", "Home");
    }

Here is the error I'm getting:

Server Error in '/' Application.

The given key was not present in the dictionary.

Description: An unhandled exception occurred during the execution of the current web     request. Please review the stack trace for more information about the error and where it     originated in the code. 

Exception Details: System.Collections.Generic.KeyNotFoundException: The given key was     not present in the dictionary.

Source Error: 

Line 1423:            
Line 1424:            if(this._dirtyColumns.Count>0)
Line 1425:                _repo.Update(this,provider);
Line 1426:            OnSaved();
Line 1427:       }

Source File: D:\Users\Mike\Documents\Visual Studio    2008\Projects\dolphin\src\ServiceDesk.Web\Models\_Generated\ActiveRecord.cs    Line:     1425 

Can anyone offer some assistance?

Here is the stack trace:
[KeyNotFoundException: The given key was not present in the dictionary.]
System.ThrowHelper.ThrowKeyNotFoundException() +28
System.Collections.Generic.Dictionary2.get_Item(TKey key) +7456284
SubSonic.Extensions.Database.ToUpdateQuery(T item, IDataProvider provider) +642
SubSonic.Repository.SubSonicRepository
1.Update(T item, IDataProvider provider) +113
ServiceDesk.Data.User.Update(IDataProvider provider) in D:\Users\Mike\Documents\Visual Studio 2008\Projects\dolphin\src\ServiceDesk.Web\Models_Generated\ActiveRecord.cs:1425
ServiceDesk.Data.User.Save(IDataProvider provider) in D:\Users\Mike\Documents\Visual Studio 2008\Projects\dolphin\src\ServiceDesk.Web\Models_Generated\ActiveRecord.cs:1461
ServiceDesk.Data.User.Save() in D:\Users\Mike\Documents\Visual Studio 2008\Projects\dolphin\src\ServiceDesk.Web\Models_Generated\ActiveRecord.cs:1452
ServiceDesk.Web.Controllers.SettingController.Edit(FormCollection result) in D:\Users\Mike\Documents\Visual Studio 2008\Projects\dolphin\src\ServiceDesk.Web\Controllers\SettingController.cs:48
lambda_method(ExecutionScope , ControllerBase , Object[] ) +140
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +17
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary2 parameters) +178
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary
2 parameters) +24
System.Web.Mvc.<>c__DisplayClassa.b__7() +52
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func1 continuation) +254
System.Web.Mvc.<>c__DisplayClassc.<InvokeActionMethodWithFilters>b__9() +19
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList
1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +192
System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +399
System.Web.Mvc.Controller.ExecuteCore() +126
System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +27
System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +7
System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) +151
System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) +57
System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) +7
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +181
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

Looks like the problem is in this code:

public static ISqlQuery ToUpdateQuery<T>(this T item, IDataProvider provider) where T : class, new()
    {
        Type type = typeof(T);
        var settings = item.ToDictionary();

        ITable tbl = provider.FindOrCreateTable<T>();

        Update<T> query = new Update<T>(tbl.Provider);
        if(item is IActiveRecord)
        {
            var ar = item as IActiveRecord;
            foreach(var dirty in ar.GetDirtyColumns())
            {
                if(!dirty.IsPrimaryKey && !dirty.IsReadOnly)
                    query.Set(dirty.Name).EqualTo(settings[dirty.Name]);
            }
        }  

dirty.Name = "FirstName" but settings["FirstName"] doesn't exist, however settings["Firstname"] does exist. My columns in the db are named like "FirstName", "LastName", etc but subsonic ActiveRecord template named the object fields like "Firstname" and "Lastname"

Best Answer

My first guess is that TimeZone is a reserved word in C# (System.TimeZone) and while this really shouldn't matter - it's the first thing I can think of. The Key error could be that SubSonic is trying to find a property with the name "TimeZone" that has been renamed - check your Structs.cs class/User table to see if that's the case.

If so please file a bug. If not - a stack trace would help.