- The View
- only post the key fields and changed fields
- The controller action
- transform the post into a DTO and ensure key is set
- validate changed fields
- The domain layer
- accept the DTO and the list of changed properties
- validate all business logic
- The Service layer
- accept the DTO
- update ONLY the changed columns.
- without fetching a new copy of the object
Goal completed.
1. In the View every input has a wrapper div marked with `data-original="@Model.oldValue"`
OnClick for the save button(s): javascript marks all input fields that have changed to `disabled='disabled'`
2. In the controller action the params required are simply the key fields. I new-up a DTO, and TryUpdateModel on it. For some reason I had to manually set the key property.
3. Domain layer is a simple pass through for now, no business logic is present yet.
4. Service Layer takes in the DTO (as an interface), maps it into a concrete type, and iterates the list of changed property names, setting the ObjectStateManager to modified for each property.
1. For Instance:
<div class="editor-label">
@Html.LabelFor(model => model.Threshold3)
</div>
<div class="editor-field" data-original="@Model.Threshold3">
@Html.EditorFor(model => model.Threshold3)
@Html.ValidationMessageFor(model => model.Threshold3)
</div>
<p>
<input type="submit" value="Save" />
</p>
and
<script type="text/javascript">
$(document).ready(function () {
$('input[type="submit"]').on('click', function () {
$('.editor-field').each(function (index,e) {
var input = $('input', e);
var old = $(e).attr('data-original');
if (typeof (old) !== 'undefined' && old !== false && old == $(input).val()) {
input.attr('disabled', 'disabled');
}
});
});
});
</script>
More after the break...
2.
public virtual ActionResult DealActivityEdit(long id)
{
ViewBag.Edit = true;
if (Request.HttpMethod == "POST")
return DealActivityEditPost(id);
var model = dealActivity.Find(f => f.ID == id).FirstOrDefault();
return View(MVC.EF.Views.DealActivityCreate, model);
}
ActionResult DealActivityEditPost(long id)
{
var posted=new DealActivityDTO();
TryUpdateModel(posted);
posted.ID = id;
var keys=Request.Form.Keys.Cast<string>().Distinct();
this.dealActivity.Update(posted, keys);
//this.dealActivityUpdates.Update(Tuple.Create(model.ID),model);
return Content("Would have edited deal activity " + id.ToString());
}
3. Pass through not yet created, I went straight to the service layer for testing =/
4.
/// <summary>
/// Update
/// </summary>
IDealActivity Core.Behaviors.IRepository<IDealActivity>.Update(IDealActivity item, IEnumerable<string> propertyList)
{
var concrete=Core.SyntaxSugar.Helpers.MapUsingSerializer<DealActivity>(item);
this.DealActivities.Attach(concrete);
foreach(var p in propertyList)
ObjectStateManager.GetObjectStateEntry(concrete).SetModifiedProperty(p);
this.SaveChanges();
return concrete;
}
Thoughts:
The post needs to be Ajax so that if the post fails, the user doesn't lose anything, and we don't have to return a new copy of the item from the database for editing. Also, after the post to the client is done, we're re-inflating to a DTO, which is a problem for serialization and transfer to other layers, unless we use JSON for that then all the empties don't have to be included.
Other Helpers:
- Ninject
- T4 all over
- T4Mvc
- Ef's .tt file modifications
- My own T4 DTO generator which copies attributes down to the DTO from the interface
- Static Reflection
- Query Interception
- Rewrites the queries from the domain into EF friendly types
- For Example:
/// <summary> /// Class to enable business logic to query a source without knowing implementation of the source /// </summary> [System.CodeDom.Compiler.GeneratedCode("T4","1.0.0.0")] IQueryable<IDealActivity> Core.Behaviors.IRepository<IDealActivity>.Query() { var generalExpWriter=new ExpressionWriter(new DebugTextWriter()); var provider=InterceptingProvider.Intercept(new ExpressionWriter(new DebugTextWriter("Underlying IDealActivity")), this.DealActivities.Select<DealActivity,IDealActivity>(c=>c), new ExpressionWriter(new DebugTextWriter()),_TypeChangeVisitor ,new ExpressionWriter(new DebugTextWriter())); return provider; } public interface IRepository<T> where T : class { IQueryable<T> Query(); IEnumerable<T> Find(Expression<Func<T, bool>> where); T Create(T item); void Delete(T item); T Update(T item, IEnumerable<string> modifiedList); }

No comments:
Post a Comment