2

我开始使用 AutoMapper 并且出现了一些疑问。将 dto 映射到域模型的正确方法在哪里?我正在这样做:

DTO:

public class PersonInsert
{
    [Required]
    public string Name { get; set; }
    public string LastName { get; set; }
}

行动:

[HttpPost]
public ActionResult Insert(PersonInsert personInsert)
{
    if (ModelState.IsValid)
    {
        new PersonService().Insert(personInsert);

        return RedirectToAction("Insert");
    }

    return View("Insert");
}

服务:

public class PersonService
{
    public int Insert(PersonInsert personInsert)
    {
        var person = Mapper.Map<PersonInsert, Person>(personInsert);

        return new PersonRepository().Insert(person);
    }
}

存储库:

 public class PersonRepository
    {
        internal int Insert(Person person)
        {
            _db.Person.Add(person);
            _db.SaveChanges();

            return person.Id;
        }
     }

那么,这是正确的吗?我的服务应该知道域吗?还是我应该只在存储库中进行绑定?在 DTO 中使用 [Required] 是否正确?

4

5 回答 5

4

我几乎永远不会从 DTO 创建实体 - 我将在下面解释原因。我会使用请求对象来允许工厂方法构建实体:

要求:

public class InsertPersonRequest
{ 
    [Required] 
    public string Name { get; set; } 
    public string LastName { get; set; } 
} 

行动:

[HttpPost] 
public ActionResult Insert(InsertPersonViewModel viewModel) 
{ 
    if (ModelState.IsValid) 
    { 
        InsertPersonRequest request = InsertPersonViewModelMapper.CreateRequestFrom(viewModel);
        new PersonService().Insert(request ); 
        return RedirectToAction("Insert"); 
    } 

    return View("Insert"); 
} 

服务:

public class PersonService 
{ 
    public int Insert(InsertPersonRequest request) 
    { 
        var person = Person.Create(request.name, request.LastName);          
        return new PersonRepository().Insert(person); 
    } 
} 

存储库保持不变。

这样,创建 Person 的所有逻辑都位于 person 的 Factory 方法中,因此业务逻辑被封装在域派生字段、默认字段等中。

您正在做的问题是必须在 UI 中创建 DTO,然后将所有字段映射到实体 - 这是业务逻辑渗入服务层、UI 或任何地方的可靠方式不应该的。

请再读一遍——这是我一次又一次看到的一个非常严重的错误。

但是,我会在服务层中使用 AutoMapper 来返回 DTO:

服务:

public class PersonService 
{ 
    public PersonDto GetById(intid) 
    { 
        var person = new PersonRepository().GetById(id);
        var personDto = Mapper.Map<Person, PersonDto>(person); 
        return personDto
    } 
} 
于 2012-09-25T14:42:41.347 回答
2

这个对吗?

我个人认为让您的服务进行映射没有任何问题

[Required]在DTO中使用是否正确

不,DTO 应该没有任何业务逻辑。它们应该纯粹用于跨应用程序的不同层/层传输数据。

DataAnnotations 通常用于客户端/服务器端验证,因此,我会在您的模型中添加另一个分离并为您的操作ViewModels引入一个例如ViewModelInsert

public class PersonViewModel    
{
    [Required]
    public string Name { get; set; }
    public string LastName { get; set; }
}

public class PersonDto
{
    public string Name { get; set; }
    public string LastName { get; set; }
}

行动:

[HttpPost]
public ActionResult Insert(PersonViewModel personViewModel)
{
     if (ModelState.IsValid)
     {
         var personDto = Mapper.Map<PersonViewModel, PersonDto>(personViewModel);
         new PersonService().Insert(personDto);
         ...
      }
      ...
     }
}

服务:

public class PersonService
{
    public int Insert(PersonDto personDto)
    {
        var person = Mapper.Map<PersonDto, Person>(personDto);

        return new PersonRepository().Insert(person);
    }
}

在这种情况下,它可能看起来有点矫枉过正(考虑到唯一的区别是[Required]属性)。但是,在典型的 MVC 应用程序中,您可能希望确保您ViewModel的 s 和您的业务模型之间的清晰分离。

于 2012-09-25T14:23:50.143 回答
1

在 ASP.NET MVC 中,DTO 的典型用途是作为视图模型的一部分。Viewmodel 是一个类,它将一个到多个 DTO 组合成一个类,为视图呈现和将值发送回服务器而量身定制。

您所做的是正确的,没有问题,但是数据注释应该驻留在视图模型上,而不是 DTO 上。除非您将 DTO 称为视图模型,否则就可以了。

请阅读以下有关 ASP.NET MVC 世界中的模型(域模型)与 ViewModel 的帖子:

希望这可以帮助

于 2012-09-25T14:27:56.850 回答
1

我会说您PersonService可以被视为您的体系结构的域层(或直接位于域之上的应用程序层)的一部分,并且控制器和 DTO 位于其之上的一层。这意味着您不应在PersonService签名中引用 DTO,而应Person在此处使用域类。所以映射代码应该进入控制器。这可确保您的域逻辑不受 Web 服务合同更改的影响,这实际上可能只是使用您的PersonService. 我还将为您的存储库引入一个接口,该接口被注入到您的存储库中,PersonService因为PersonService再次不需要了解具体的数据访问实现。

至于[Required]属性,我认为在 DTO 上使用它没有问题,因为它只是说明了您的 Web 服务方法的数据合同。任何调用您的 Web 服务的人都应遵守此数据合同。当然,这个要求通常也会反映在您的域代码中的某个地方,可能是通过抛出异常等。

于 2012-09-25T14:44:05.470 回答
1

我认为在 DTO 上添加注释很好,例如 [Required]、MaxLength、Range 等。

您的 DTO 可以来自任何(可能不受信任的)来源(不仅是您的网站,还可以来自另一个端点、WCF 服务等)。所有请求都将集中到您的服务/业务层,因此您需要在执行业务逻辑之前验证输入(简单的警卫检查)。在 DTO 上添加注释只是描述了执行手头任务所需的输入。传递带有注释的对象不会执行验证。

但是,我相信您应该在服务/业务层中验证 DTO 信息是否正确(注释是检查这一点的好方法)。

只是我对这种情况的看法:)

于 2015-12-05T14:23:23.420 回答