The book is done!
1 day ago
int Insert<T>(IQueryable query,IQueryable<T> targetSet)
{
var oQuery=(ObjectQuery)this.QueryProvider.CreateQuery(query.Expression);
var sql=oQuery.ToTraceString();
var propertyPositions = GetPropertyPositions(oQuery);
var targetSql=((ObjectQuery)targetSet).ToTraceString();
var queryParams=oQuery.Parameters.ToArray();
System.Diagnostics.Debug.Assert(targetSql.StartsWith("SELECT"));
var queryProperties=query.ElementType.GetProperties();
var selectParams=sql.Substring(0,sql.IndexOf("FROM "));
var selectAliases=Regex.Matches(selectParams,@"\sAS \[([a-zA-Z0-9_]+)\]").Cast<Match>().Select(m=>m.Groups[1].Value).ToArray();
var from=targetSql.Substring(targetSql.LastIndexOf("FROM [")+("FROM [".Length-1));
var fromAlias=from.Substring(from.LastIndexOf("AS ")+"AS ".Length);
var target=targetSql.Substring(0,targetSql.LastIndexOf("FROM ["));
target=target.Replace("SELECT","INSERT INTO "+from+" (")+")";
target=target.Replace(fromAlias+".",string.Empty);
target=Regex.Replace(target,@"\sAS \[[a-zA-z0-9]+\]",string.Empty);
var insertParams=target.Substring(target.IndexOf('('));
target = target.Substring(0, target.IndexOf('('));
var names=Regex.Matches(insertParams,@"\[([a-zA-Z0-9]+)\]");
var remaining=names.Cast<Match>().Select(m=>m.Groups[1].Value).Where(m=>queryProperties.Select(qp=>qp.Name).Contains(m)).ToArray(); //scrape out items that the anonymous select doesn't include a name/value for
//selectAliases[propertyPositions[10]]
//remaining[10]
var insertParamsOrdered = remaining.Select((s, i) => new { Position = propertyPositions[i], s })
.OrderBy(o => o.Position).Select(x => x.s).ToArray();
var insertParamsDelimited = insertParamsOrdered.Aggregate((s1, s2) => s1 + "," + s2);
var commandText = target + "(" + insertParamsDelimited + ")" + sql;
var result=this.ExecuteStoreCommand(commandText,queryParams.Select(qp=>new System.Data.SqlClient.SqlParameter{ ParameterName=qp.Name, Value=qp.Value}).ToArray());
return result;
}
With some help from http://stackoverflow.com/questions/7808607/how-does-entity-framework-manage-mapping-query-result-to-anonymous-type and http://msdn.microsoft.com/en-us/library/ee358769.aspx
public class ScenarioCreationDTO
{
[Required]
[StringLength(500)]
public string Comments { get; set; }
[Required]
public IEnumerable<int> PriceLists { get; set; }
public IEnumerable<PriceListCurrencyDTO> Currencies { get; set; }
public IEnumerable<PriceListCountryDTO> Countries { get; set; }
}
Currencies has a compound key. How do I get binding to work for either checkBoxList or RadioButtons? Sometimes the user is allowed to select multiple, other times not.
Perhaps the problem was in the view?
<tbody>
@foreach (SelectListItem item in ViewBag.CurrencySelect)
{
<tr>
<td>
@if (ViewBag.MultipleCurrencies)
{
@Html.RadioButton("currencies", item.Value, item.Selected)
}
@Html.Label(item.Text)
</td>
</tr>
}
</tbody>
I did not find a RadioButtonList helper, nor a RadioButtonFor<T> that took multiple values.
Thanks to Msdn magazine and Buildstarted.com
I now have a custom model binder.
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
ModelBinders.Binders.Add(typeof(PriceListCurrencyDTO),new PriceListCurrencyBinder());
- global.asax.cs
public class PriceListCurrencyBinder:IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
ValueProviderResult value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
var selected = value.AttemptedValue;
var result = Shared.SyntaxSugar.Helpers.Deserialize<PriceListCurrencyDTO>(selected);
return result;
}
}
var currencySelect=currencies.Select(c => new SelectListItem()
{
Text = c.CurrencyCode,
Value = Shared.SyntaxSugar.Helpers.Serialize(c),
Selected = priceListCurrenciesSelected != null && priceListCurrenciesSelected.Any(plc=>c.PriceListID==plc.PriceListID && c.CurrencyCode==plc.CurrencyCode)
}).ToArray();
ViewBag.CurrencySelect = currencySelect;
[HttpPost]
public virtual ActionResult Create(byte regionID, Int64 dealID, Model.ViewModel.Scenarios.ScenarioCreationDTO data){
//...
}
and finally the view
<tbody>
@foreach (SelectListItem item in ViewBag.CurrencySelect)
{ var i=-1; i++;
<tr>
<td>
@if (ViewBag.MultipleCurrencies)
{
@Html.RadioButton("currencies["+i+"]", item.Value, item.Selected)
}
@Html.Label(item.Text)
</td>
</tr>
}
</tbody>
<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>
<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>