在给定以下模型的情况下,设计用于MVC或Web Api模型绑定的DTO(尚未决定使用哪个)的最佳方法是什么,将使用实体框架:
public class Actor
{
public int ActorId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public List<ActorPhone> ActorPhones { get; set; }
public List<ActorEmail> ActorEmails { get; set; }
public List<ActorAddress> ActorAddresses { get; set; }
}
public class ActorAddress
{
public int AddressId { get; set; }
public int ActorId { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
public class ActorEmail
{
public int ActorEmailId { get; set; }
public int ActorId { get; set; }
public string Email { get; set; }
}
public enum ActorPhoneType
{
HomePhone,
WorkPhone,
Fax
}
public abstract class ActorPhone
{
public int ActorId { get; set; }
public int ActorPhoneId { get; set; }
public ActorPhoneType PhoneType { get; }
public string Phone { get; set; }
public ActorPhone(ActorPhoneType phoneType)
{
this.PhoneType = phoneType;
}
}
public class ActorHomePhone : ActorPhone
{
public ActorHomePhone() : base(ActorPhoneType.HomePhone) { }
}
public class ActorWorkPhone : ActorPhone
{
public ActorWorkPhone() : base(ActorPhoneType.WorkPhone) { }
}
public class ActorFax : ActorPhone
{
public ActorFax() : base(ActorPhoneType.Fax) { }
}
虽然地址和电子邮件可以有多个实体,而演员应该只有一个家庭电话,一个工作电话和一个传真。
数据库有一个表ActorPhones,将从中存储派生类型。
如何在MVC或Web API控制器中处理模型绑定。表单输入字段应该命名为什么?
例如,有这种方法:
<input name="Actor.ActorPhones[0].Phone" type="text"/>
这种方法:
<input name="Actor.HomePhone.Phone" type="text"/>
还有一种方法是将每个作为字符串属性公开在Actor上。
public class Actor
{
public int ActorId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string HomePhone { get; set; }
public string WorkPhone { get; set; }
public string Fax { get; set; }
public List<ActorEmail> ActorEmails { get; set; }
public List<ActorAddress> ActorAddresses { get; set; }
}
使用:
<input name="Actor.HomePhone" type="text"/>
<input name="Actor.WorkPhone" type="text"/>
<input name="Actor.Fax" type="text"/>
使用第一个,我需要为手机类型添加额外的输入。第二个和第三个需要自定义逻辑才能将模型绑定到dbset。
此外,数据库中可能有数百万个参与者,出于性能原因,不应该有空电话号码。第一种和第三种方法还需要自定义逻辑来通过PhoneType检查ActorPhones列表并删除或添加ActorPhone实体及其底层DBS。例如,如果演员没有数据库中的传真号码记录,则不应添加该记录,因此需要自定义逻辑。
所以让我们说我们使用第一种方法,我们的第一个Actor有一个家庭电话,只有视图可以在表单上轻松地呈现以下模型中的Actor Phones列表:
<input name="Actor.ActorPhones[0].Phone" type="text" required/>
<input name="Actor.ActorPhones[0].PhoneType" type="hidden" value="HomePhone"/>
对第二个拥有家庭电话和工作电话的演员使用第一种方法,以便表格具有:
<input name="Actor.ActorPhones[0].Phone" type="text" required/>
<input name="Actor.ActorPhones[0].PhoneType" type="hidden" value="HomePhone"/>
<input name="Actor.ActorPhones[0].Phone" type="text" required/>
<input name="Actor.ActorPhones[1].PhoneType" type="hidden" value="WorkPhone"/>
使用此方法控制器视图可以轻松地在表单上呈现模型。
使用第二种方法,我们的视图需要查看每个Actor.HomePhone
,Actor.WorkPhone
或Actor.Fax
导航属性是否为空,如果它们不呈现相应的{ {1}},<input name="Actor.HomePhone.Phone" type="text"/>
或<input name="Actor.WorkPhone.Phone" type="text"/>
。这可能需要自定义逻辑,可能通过服务器端的服务,但有助于使用工厂设计模式。
使用第三种方法<input name="Actor.Fax.Phone" type="text"/>
,Actor.HomePhone
,Actor.WorkPhone
作为字符串属性,视图需要检查字段是否为空且值不是emtpy呈现相应的Actor.Fax
,<input name="Actor.HomePhone" type="text"/>
或<input name="Actor.WorkPhone" type="text"/>
字段。另外,在服务器端,将需要定制逻辑,例如通过服务。但我不确定采用这种方法的最佳设计模式。第三种方法也没有直接在数据库中实现以节省空间。如果添加到actors表中的家庭电话,工作电话和传真被定义为varchar(20),则数据库将需要额外的20 * 3 * 1,000,000 = 60,000,000字节或每百万条记录60 mb。