2017-07-28 62 views
2

我正在研究ASP.NET MVC Web应用程序。 我目前的架构是这样的:将DTO传递给服务层进行CRUD操作

Presentation Layer <--> Service Layer <--> Data Access Layer 

数据访问层包含EF实体模型。 服务层从数据访问层检索EF实体模型并返回DTO。 表示层从服务层检索DTO,并将ViewModels返回到视图。

我的问题是关于我应该将哪些类传递给驻留在我的服务层中的创建和更新函数。例如:

实体模型:

public class User 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; }  
    public string LastName { get; set; }    
    public int UserTypeId { get; set; } 

    public virtual UserType UserType { get; set; } 
} 

public class UserType 
{ 
    public int Id { get; set; } 
    public string Name { get; set; }     

    public virtual UserType UserType { get; set; } 
} 

DTO:

public class UserDTO 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; }     
    public int UserTypeId { get; set; } 

    //Note this "extra" field 
    public string UserTypeName { get; set; }   
} 

服务层功能:

public class UserService: IUserService 
{ 
    public UserDTO GetUser(int userId) 
    { 
     //The UserType.Name is used a lot, so I'd rather include it in this one db call 
     //rather than use a separate db call to get the name based on the UserTypeId 

     return _dbContext.Users.Where(u => u.Id == userId) 
        .Select(u => new UserDTO 
        { 
         Id = u.Id, 
         FirstName = u.FirstName, 
         LastName = u.LastName, 
         UserTypeId = u.UserTypeId, 

         UserTypeName = u.UserType.Name 
        } 
        .First(); 
    } 

    //?? 
    public void EditUser(UserDTO userDto) 
    { 
     //Should I use this? Or EditUser(EditUserDTO editUserDto)...  
    } 

    //?? 
    public void EditUser(EditUserDTO editUserDto) 
    { 
     //Should I use this? Or EditUser(UserDTO userDto)... 
     //Note EditUserDTO looks like UserDTO but does not have UserTypeName 
    } 
} 

你会看到我的困惑是因为使用什么类EditUser(...)的参数。

  • 如果我使用EditUser(UserDTO userDto),那么如何将其他开发商 知道他们需要设置UserDTO.UserTypeName?他们 只需要设置UserTypeId。
  • 如果我使用EditUser(EditUserDTO editUserDto),那么开发人员将知道 准确设置哪些信息(EditUserDTO中的每个属性)。但它是一个额外的类来维护,映射和使用。

一些建议:

  1. 我能有DTO实体模型精确相符,但是那有什么用DTO的意义呢?
  2. 而不是有一个“扁平”的DTO,我可以有一个UserTypeDTO类作为UserDTO的一个属性。我认为这会让事情变得更加清晰,但在调用EditUser(UserDTO)时仍然不需要设置。 侧面问题:DTO是否应该是“平坦”的最佳做法?
  3. 任何其他想法...?

感谢您的帮助!

回答

1

我建议使用单独的DTO定义进行获取和编辑操作。那么消费者就不可能设置他们不应该做的事情。所以我会说EditUser方法使用EditUserDTO

更新

要多一点背景添加到我的回答。

使用DTO的想法是将您的底层DAL抽象出来。通常有更多的数据存储在您的数据层中,而不是从您的服务层返回,或者您的实体可能没有您想要发送回调用者的相同结构,因此通过创建DTO,您可以隐藏这个远。这也使您可以选择更改DAL并保持服务层的公共契约相同,以便消费者在内部更改某些内容时不必重新编写代码。

DTO's可以是平坦的或有层次结构。这实际上取决于保持DTO是否平坦或具有层次结构是否合理。以您的示例UserDTO为例,除非您要返回UserDTO中的UserTypes树,否则您应该将其保留为简单的“扁平”DTO。

+0

我同意所有关于DTO提供的利益的陈述。我倾向于同意你关于使用单独的DTO获取和编辑的答案。我只是没有看到像这样的完整例子。我看到的大多数示例都使用相同的DTO,但示例中的DTO倾向于完全匹配实体模型.... 了解任何示例或教程@Darren? –

+0

最近我一直在研究一些REST API。例如,DAL返回有关用户个人资料的信息,包括评分等内容,如果他们是经过验证的用户以及哈希和密码。当应用程序获得特定的用户配置文件时,它们的当前分数和一个表示它们是否被验证的“bool”被返回,我们不会因为明显的原因返回密码哈希值。当用户编辑他们的个人资料时,这些服务不允许他们编辑他们的分数,或者他们是否被验证,因为这些都是应用程序使用或管理功能的产品。所以我们为这些使用单独的DTO。 –

+0

希望得到一个在线/物理的例子,但一个轶事的例子:)。是的,我绝对看到在这种情况下单独的DTO是多么有意义。 如果您不介意,我还有另一个关于DTO的问题: https://stackoverflow.com/questions/45382492/validating-data-in-the-service-layer-against-dtos-entity-models-or-一些-E –