MVC 3,EntityFramework 4.1,数据库优先,Razor定制:
我有一个旧数据库,有时使用Int16或Char类型作为必须在MVC _CreateOrEdit.cshtml视图中显示为CheckBox的字段。如果是Int,则1 = true且0 = false。如果是Char,则“Y”=真,“N”=假。这对于实体框架来说自动转换太多了。对于详细信息视图,我可以使用:
@Html.CheckBox("SampleChkInt", Model.SampleChkInt==1?true:false)
但是在_CreateOrEdit.cshtml视图中,这不能代替EditorFor。 这该怎么做?我在想一个自定义的HtmlHelper,但我发现的例子并没有告诉我如何告诉EntityFramework正确更新数据库。还有其他我可能想要做的自定义,其中MVC View与数据库不完全匹配,以便EntityFramework进行更新。回答这个问题就是一个很好的例子。我正在研究一个示例项目,使用以下自动生成的(因此我无法对其进行更改)模型类:
namespace AaWeb.Models
{
using System;
using System.Collections.Generic;
public partial class Sample
{
public int SampleId { get; set; }
public Nullable<bool> SampleChkBit { get; set; }
public Nullable<short> SampleChkInt { get; set; }
public Nullable<System.DateTime> SampleDate { get; set; }
public string SampleHtml { get; set; }
public Nullable<int> SampleInt { get; set; }
public Nullable<short> SampleYesNo { get; set; }
public string Title { get; set; }
public byte[] ConcurrencyToken { get; set; }
}
}
答案 0 :(得分:1)
我明白了。不需要模型绑定器或Html Helper扩展:
在_CreateOrEdit.cshtml中,我为复选框创建了一个新名称SampleChkIntBool,并根据模型SampleChkInt的值设置它:
@Html.CheckBox("SampleChkIntBool", Model == null ? false : ( Model.SampleChkInt == 1 ? true : false ), new { @value = "true" })
然后,在Sample.Controller的[HttpPost] Create和Edit方法中,我使用Request [“SampleChkIntBool”]获取SampleChkIntBool的值,并在保存之前使用它来设置模型SampleChkInt:
string value = Request["SampleChkIntBool"];
// @Html.CheckBox always generates a hidden field of same name and value false after checkbox,
// so that something is always returned, even if the checkbox is not checked.
// Because of this, the returned string is "true,false" if checked, and I only look at the first value.
if (value.Substring(0, 4) == "true") { sample.SampleChkInt = 1; } else { sample.SampleChkInt = 0; }
答案 1 :(得分:0)
答案 2 :(得分:0)
以下是从复选框到数据库的方法,没有控制器中的特殊代码:
// The following statement added to the Application_Start method of Global.asax.cs is what makes this class apply to a specific entity:
// ModelBinders.Binders.Add(typeof(AaWeb.Models.Sample), new AaWeb.Models.SampleBinder());
// There are two ways to do this, choose one:
// 1. Declare a class that extends IModelBinder, and supply all values of the entity (a big bother).
// 2. Declare a class extending DefaultModelBinder, and check for and supply only the exceptions (much better).
// This must supply all values of the entity:
//public class SampleBinder : IModelBinder
//{
// public object BindModel(ControllerContext cc, ModelBindingContext mbc)
// {
// Sample samp = new Sample();
// samp.SampleId = System.Convert.ToInt32(cc.HttpContext.Request.Form["SampleId"]);
// // Continue to specify all of the rest of the values of the Sample entity from the form, as done in the above statement.
// // ...
// return samp;
// }
//}
// This must check the property names and supply appropriate values from the FormCollection.
// The base.BindProperty must be executed at the end, to make sure everything not specified is take care of.
public class SampleBinder : DefaultModelBinder
{
protected override void BindProperty( ControllerContext cc, ModelBindingContext mbc, System.ComponentModel.PropertyDescriptor pd)
{
if (pd.Name == "SampleChkInt")
{
// This converts the "true" or "false" of a checkbox to an integer 1 or 0 for the database.
pd.SetValue(mbc.Model, (Nullable<Int16>)(cc.HttpContext.Request.Form["SampleChkIntBool"].Substring(0, 4) == "true" ? 1 : 0));
// To do the same in the reverse direction, from database to view, use pd.GetValue(Sample object).
return;
}
// Need the following to get all of the values not specified in this BindProperty method:
base.BindProperty(cc, mbc, pd);
}
}