当前位置:  开发笔记 > 编程语言 > 正文

Slick 3:如何使用事务实现存储库模式?

如何解决《Slick3:如何使用事务实现存储库模式?》经验,为你挑选了1个好方法。

在我的play framework(2.5)app中,我需要为服务编写单元测试.

我需要隔离数据访问逻辑以便能够单独测试服务层,为此我想创建存储库接口并在我的单元测试中对它们进行MOCK:

class UserService {
   def signUpNewUser(username: String, memberName: String): Future[Unit] {
      val userId = 1 // Set to 1 for demo
      val user = User(userId, username)
      val member = Member(memberName, userId) 
      // ---- I NEED TO EXECUTE THIS BLOCK WITHIN TRANSACTION ----
      for {
        userResult <- userRepository.save(user)
        memberRepository.save(member)
      } yield ()     
      // ---- END OF TRANSACTION ----
   }
}

在上述例子中,userRepository.save(User)memberRepository.save(member)操作应当事务中执行.

我不想直接在我的服务层使用光滑,因为它会使我的测试复杂化.

另外,我不想在我的单元测试中使用嵌入式数据库,在其他地方它将是一个NOT单元测试,我需要完全隔离.

我不希望我的存储库接口完全依赖于光滑,但是需要这样的东西:

trait UserRepository {
   findById(id: Long): Future[Option[User]]
   save(user: User): Future[Unit] 
}

如何用光滑实现这一目标?



1> Paul Dolega..:

好的-让我们将您的问题分解为三个部分。

如何在交易中执行区块

基本上读这个答案:如何在光滑的使用交易

一旦转换DBIOFuture您,就完成了。没有机会在单个交易中进行多个操作。故事结局。

如何避免Slick在测试中使用

这基本上是一个设计问题-如果您想在Repository/ DAO/ 之上建立一个业务层-而不是让该服务层处理事务。您无需与Slick该层外部进行交互。

避免依赖您的存储库接口 Slick

以最直接的方式-您需要依靠Slick DBIO在事务Repository内编写操作(在事务内编写方法是您在任何严肃的应用程序中都无法避免的)。

如果要避免依赖,DBIO可能会创建自己的单子类型,请说TransactionBoundary[T]TransactionContext[T]

然后,您将TransactionManager执行类似的操作TransactionContext[T]

恕我直言,这不值得花些功夫,我只想使用DBIO一个已经有了一个好名字的名字(就像Haskell的IOmonad一样-会DBIO告诉您您已经IO对存储执行的操作进行了描述)。但让我们假设您仍然想要避免这种情况。

您可能会做类似的事情:

package transaction {

  object Transactions {
    implicit class TransactionBoundary[T](private[transaction] val dbio: DBIO[T]) {
      // ...
    }
  }

  class TransactionManager {
    def execute[T](boundary: TransactionBoundary[T]): Future[T] = db.run(boundary.dbio)
  }
}

您的特征将如下所示:

trait UserRepository {
   findById(id: Long): TransactionBoundary[Option[User]]
   save(user: User): TransactionBoundary[Unit] 
}

在代码中的某处,您会这样:

transactionManager.execute(
    for {
        userResult <- userRepository.save(user)
        memberRepository.save(member)
    } yield ()  
)

通过使用隐式转换,您可以将方法的结果Repository自动转换为TransactionBoundary

但是同样,恕我直言,以上所有这些都没有给使用带来任何实际的好处DBIO(除了审美趣味之外)。如果要避免Slick在特定层之外使用相关类,只需创建一个如下类型的别名:

type TransactionBoundary[T] = DBIO[T]

并在任何地方使用它。

推荐阅读
重庆制造漫画社
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有