搜索

首页  >  问答  >  正文

避免在存储库层中包含领域逻辑

在我当前的应用程序中,我需要创建一个 api GET 路由“/inactive-users”,它应该返回已存档的用户(“isArchived”),并且同时处于非活动状态超过一个月("lastVisitedDate" 字段应早于 new Date() - 1 个月)。

采用分层架构(控制器/服务/存储库),领域模型贫乏,这种情况下我该怎么办?

我看到有两种可能的方法。

1 - 创建通用存储库方法来获取用户并将我们需要的用户字段传递给它。

@Injectable()
export class UserRepository {
  constructor(private readonly prisma: PrismaService) { }

  findAll = async ( where: { user: Partial<User>; dateTreshold: Date } ): Promise<User[]> => {
    const users = await this.prisma.user.findMany(
      { where: {...user}, lastVisitedDate: { lt: dateTreshold }; // lt - less than
    );
        
    return users.map(user => new User(user));
  }
}

@Injectable()
export class UserService {
  constructor(private readonly userRepository: UserRepository) {}
  
  getInactiveUsers = async () => {
    return this.userRepository.findAll(
      { where: {user: {isArchived: true}, dateTreshold: "// calculatedDate //"}
    ) 
  }
}

2 - 准确地创建存储库方法来检索不活动的用户,该方法将知道它应该请求哪些字段。

@Injectable()
export class UserRepository {
  constructor(private readonly prisma: PrismaService) { }

  getInactiveUsers = async (): Promise<User[]> => {
    const users = await this.prisma.user.findMany(
      { where: {isArchived: false, lastVisitedDate: { lt: "// calculatedDate //" }}; // lt - less than
    );
        
    return users.map(user => new User(user));
  }
}

@Injectable()
export class UserService {
  constructor(private readonly userRepository: UserRepository) {}
  
  getInactiveUsers = async () => {
    return this.userRepository.getInactiveUsers() 
  }
}

哪种方式更好? 第一个对我来说看起来不错,因为在这种情况下,存储库对“非活动”用户的域理解一无所知。但与此同时 - 构建这样一个响应式方法可能相当困难。

第二种方式更容易构建,但同时 - 它具有一些“业务”逻辑理解,并且知道不活动用户是那些 "isArchived" 等于 false 的用户。而且,这个存储库方法知道我们需要使用的天数。

在这种情况下应该选择哪个选项?或者也许还有其他方法来构建这个东西?

P粉151720173P粉151720173230 天前548

全部回复(1)我来回复

  • P粉118698740

    P粉1186987402024-04-02 19:39:22

    分离此问题的正确方法是存储库仅了解存储库中的数据元素。这并不意味着您的存储库中不能有多个入口点,可能有许多不同的查询都访问相同的“表”。

    这并不意味着您需要像第一种方法那样的完整 QBE,请保持简单。有一个封装数据库层位的查询,但仍然要求它需要的东西。

    在这种情况下,您应该有一个传递 isArchived 和 lastVisitedDate 参数的签名。类似 QueryUsersByStatusAndLastVisited 之类的东西。这样,存储库可以处理与检索数据有关的所有位,但没有关于为什么检索它们的逻辑。它将是“哑巴”的,所有智能位都封装在服务层。

    回复
    0
  • 取消回复