I've used a slightly more complicated variation of the following pattern:
protected ActionResult Update<T>(Expression<Func<T, bool>> predicate, Action<IDataContext, T> action, params string[] whitelist) where T : class
{
using (var context = ContextFactory.GetContext())
{
try
{
var model = context.GetTable<T>().Where(predicate).SingleOrDefault();
if (model == null) throw new ApplicationException("Item not found");
if (whitelist != null && whitelist.Length > 0)
{
TryUpdateModel(model, whitelist);
}
else
{
TryUpdateModel(model);
}
if (action != null) action(context, model);
context.SubmitChanges();
return Success();
}
catch (SqlException ex)
{
return HandleSqlException(ex);
}
catch (Exception ex)
{
return Failure();
}
}
}
This allows you to write a basic Update action as simple as:
public ActionResult Update(int id)
{
return Update<Customer>(c => c.CustomerID == id);
}
This uses a different overload of the above code, where the Action<,>
isn't passed in, which is used to allow you to inject custom binding code if TryUpdateModel
does not suffice. For example:
public ActionResult Update(int id)
{
return Update<Customer>
(
c => c.CustomerID == id,
(context, c) =>
{
c.LastModified = DateTime.Now;
}
);
}
It's not flexible enough for all update cases, but probably suffices for most dumb CRUD scenarios. You can use this to centralize your exception handling, logging, mapping of difficult kinds of properties (mainly booleans, because checkboxes are not posted in HTML if they're unchecked, but also nullable value types).