使用派生类进行MVC WebAPI DTO模型绑定的最佳方法

时间:2017-07-01 22:06:36

标签: c# asp.net-mvc entity-framework asp.net-web-api

在给定以下模型的情况下,设计用于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.HomePhoneActor.WorkPhoneActor.Fax导航属性是否为空,如果它们不呈现相应的{ {1}},<input name="Actor.HomePhone.Phone" type="text"/><input name="Actor.WorkPhone.Phone" type="text"/>。这可能需要自定义逻辑,可能通过服务器端的服务,但有助于使用工厂设计模式。

使用第三种方法<input name="Actor.Fax.Phone" type="text"/>Actor.HomePhoneActor.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。

0 个答案:

没有答案