如何在WebAPI控制器中使用DTO?

时间:2016-11-12 11:40:45

标签: c# asp.net-web-api entity-framework-6 dto ado.net-entity-data-model

我有点困惑如何在我的WebAPI控制器中使用DTO。我正在使用数据库第一个实体框架概念。生成了以下实体数据模型:

//Generated class by EDM:
public partial class Address
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Address()
        {
            this.Member = new HashSet<Member>();
        }

        public int Id { get; set; }
        public string Street { get; set; }
        public Nullable<short> Street_Number { get; set; }
        public Nullable<decimal> Zip { get; set; }
        public string City { get; set; }
        public string Country { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Member> Member { get; set; }
    }

使用数据注释我需要定义AddressDTO,因为每当我需要修改EDM时,数据模型将再次生成并且数据注释将丢失。

接下来,我定义了AddressDTO

public class AddressDTO
    {
        public int Id { get; set; }
        [Required]
        [StringLength(100,ErrorMessage="The max. length of the street name is 100 characters.")]
        public string Street { get; set; }
        public Nullable<short> Street_Number { get; set; }
        [Required]
        public Nullable<decimal> Zip { get; set; }
        [Required]
        [RegularExpression(@"[a-z,A-Z]",ErrorMessage="Only characters are allowed.")]
        public string City { get; set; }
        [Required]
        public string Country { get; set; }
    }

控制器看起来像下面的代码:

    [RoutePrefix("api/address")]
    public class AddressController : ApiController
    {
        private PersonEntities db = new PersonEntities();

        // GET: api/Address
        [HttpGet]
        [ResponseType(typeof(AddressDTO))]
        public async Task<IHttpActionResult> GetAll()
        {
            var addressList = await db.Address.ToListAsync();

            return Ok(addressList);
        }
     }

当我启动RestAPI以在浏览器中显示结果时,我总是得到以下json结果:

[
    {
        "Member": [ ],
        "Id": 1,
        "Street": "Example Street",
        "Street_Number": 1,
        "Zip": 12345.0,
        "City": "New York",
        "Country": "USA" 
    },...
]

但我需要以下预期结果:

[
        {
            "Street": "Example Street",
            "Street_Number": 1,
            "Zip": 12345.0,
            "City": "New York",
            "Country": "USA" 
        },...
    ]

有谁知道如何解决这个问题?

2 个答案:

答案 0 :(得分:6)

您的新修改只是意味着您的Id模型中不需要MemberAddressDTO属性。当你返回List<AddressDTO>时,哟应该将结果整形为List<Address>

因此,只需从AddressDTO中移除未使用的属性,然后选择新的AddressDTO并设置属性来调整结果:

var result = db.Address.Select(x=> new AddressDTO()
                                   { 
                                       Street = x.Id, 
                                       Street_Number = x.Street_Number,
                                       City = x.City,
                                       Country = x.Country
                                   }).ToListAsync();

如果你想缩短linq,你可以将这样的构造函数添加到AddressDTO

public AddressDTO(Address x)
{
    Street = x.Id;
    Street_Number = x.Street_Number;
    City = x.City;
    Country = x.Country;
}

然后在控制器中:

var result = db.Address.Select(x=> new AddressDTO(x)).ToListAsync();

同样在一个大型项目中,您可以依赖一些对象映射器,如答案中提到的自动映射器。

答案 1 :(得分:2)

使用像Automapper这样的库来满足您的需求。

然后你只需要将以下行修改为例如:

var addressList = await Mapper.Map<IList<AddressDto>>(db.Address.ToListAsync());

这会将您的地址列表转换为AddressDto列表,您可以在其中控制转换的内容,以便不将会员传递给您的视图。如果字段名称相同,Automapper将自动知道要转换的内容。