Slick 3:如何通过事务实现存储库模式?

2024-01-18

在我的 Play Framework (2.5) 应用程序中,我需要为服务编写单元测试。

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

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) and memberRepository.save(member)操作应在事务内执行。

我不想在我的服务层中直接使用 slick,因为它会使我的测试变得复杂。

另外,我不想使用嵌入式数据库进行单元测试,在其他地方它将不是单元测试,我需要完全隔离。

我根本不希望我的存储库接口依赖于 slick,但需要这样的东西:

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

我怎样才能用光滑实现这个目标?


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

如何在交易中执行区块

基本上读了这个答案:如何在slick中使用事务 https://stackoverflow.com/questions/41219200/how-to-use-transaction-in-slick/41219465#41219465

一旦您转换DBIO to Future你完成了。没有机会在单个事务中组成多个操作。故事结局。

如何避免使用Slick在测试中

这基本上是一个设计问题 - 如果你想在之上有一个业务层Repository / DAO/ 无论如何 - 让这个服务层处理事务。您无需与Slick在这一层之外。

避免依赖存储库接口Slick

以最直接的方式 - 您需要依赖 SlickDBIO在事务中组合操作(并组合Repository事务中的方法是任何严肃的应用程序中都无法避免的)。

如果你想避免依赖于DBIO你也许会创建你自己的一元类型,比如说TransactionBoundary[T] or TransactionContext[T].

然后你会得到类似的东西TransactionManager这将执行这个TransactionContext[T].

恕我直言,不值得付出努力,我只是使用DBIO它已经有了一个辉煌的名字(就像 Haskell 的IO单子-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]

并在任何地方使用它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Slick 3:如何通过事务实现存储库模式? 的相关文章

  • 如何找到两个数据帧之间的精确和非精确匹配?

    我有两个数据框 df1 id amount fee 1 10 00 5 0 2 20 0 3 0 3 90 130 0 4 120 0 35 0 df2 exId exAmount exFee 1 10 00 5 0 2 20 0 3 0
  • Spark DataFrame 不尊重架构并将所有内容视为字符串

    我面临着一个多年来一直无法克服的问题 我使用的是 Spark 1 4 和 Scala 2 10 我现在无法升级 大型分布式基础设施 我有一个包含几百列的文件 其中只有 2 列是字符串 其余都是长列 我想将此数据转换为标签 特征数据框 我已经
  • RSpec 与 Shoulda?

    我是单元测试场景的新手 我现在只使用单元测试大约两个月了 当我在 Ruby 中进行单元测试时 我目前遵循 TDD 风格并使用 Test Unit TestCase 我还阅读了 RSpec 以及它如何遵循 BDD 方法 我还读过关于 Shou
  • 如何强制 Spark 执行代码?

    我如何强制 Spark 执行对 map 的调用 即使它认为由于其惰性求值而不需要执行它 我试过把cache 与地图调用 但这仍然没有解决问题 我的地图方法实际上将结果上传到 HDFS 所以 它并非无用 但 Spark 认为它是无用的 简短回
  • Scala:不变性和路径依赖的类型兼容性

    我围绕这个主题提出了一些问题 但这次我想让它成为一个更一般性的讨论 因为在我看来 Scala 缺少一些非常重要的块 考虑以下代码 从我的真实项目中简化 trait World type State lt StateIntf def evol
  • 与解构一起使用的Sinon存根函数

    我希望对我当前正在测试的文件中使用的函数进行存根 解构时需要此函数 如下所示 const theFunctionIWant require path to module 测试时 永远不会调用存根 而是继续调用实际函数 但是当我 正常 需要它
  • 带有泛型参数的抽象类的 JsonFormat

    我正在尝试为具有通用参数的抽象类编写 JsonFormat 如下所示 abstract class Animal A def data A def otherStuff String stuff case class CatData cat
  • TestMethod:异步任务 TestSth() 不适用于 .NET 4.0

    我正在尝试使用 NET 4 0 BCL Async 和 MsTest 运行异步测试方法 看来这个设置不能处理 测试方法 异步Task测试Sth 由于测试用例资源管理器中缺少条目 将签名更改为异步后void 我可以运行测试用例 但结果错误 根
  • 最大模式长度 fpgrowth apache Spark

    我正在尝试使用 Spark Scala 运行关联规则 我首先创建一个 FPGrowth 树并将其传递给关联规则方法 但是 我希望添加最大模式长度参数 以限制我想要在左侧和右侧的项目数量 我只想要项目之间的一对一关联 val model ne
  • 无法在单元测试中检查响应标头

    我有一个 Http 处理程序的单元测试 在其中我创建了一个HttpResponse对象并将其传递给我的 Http 处理程序的方法之一 我的一项测试尝试验证响应标头是否已正确设置 Assert AreEqual gzip response H
  • 如何为 Inquirer.js 编写单元测试?

    我想知道如何为 npm 包编写单元测试询问者 js https github com SBoudrias Inquirer js 这是一个让CLI打包更容易的工具 我读过了这个帖子 https glebbahmutov com blog u
  • 模拟 EF core dbcontext 和 dbset

    我正在使用 ASP NET Core 2 2 EF Core 和 MOQ 当我运行测试时 我收到此错误 消息 System NotSupportedException 非虚拟 可在 VB 中重写 成员上的设置无效 x gt x Movies
  • 如何在spark中将矩阵转换为RDD[Vector]

    如何转换自org apache spark mllib linalg Matrix to RDD org apache spark mllib linalg Vector 在火花 该矩阵是由 SVD 生成的 我正在使用 SVD 的结果进行聚
  • 将结构数组分解为 Spark 中的列

    我想将结构数组分解为列 由结构字段定义 例如 root arr array nullable true element struct containsNull true id long nullable false name string
  • Powermockito 可以在非最终具体类中模拟最终方法吗?

    假设我有一个非最终具体类 具有如下所示的最终方法 public class ABC public final String myMethod return test test 可以嘲笑吗myMethod 调用时返回其他内容junit usi
  • 使用反应式扩展对事件进行单元测试

    我在用着 NET 的反应式扩展 Rx http msdn microsoft com en us devlabs ee794896 aspx将事件公开为IObservable
  • Scala 宏 - 使用“c.prefix”推断隐式值

    c inferImplicitValue推断调用站点范围中的隐式值 是否可以使用推断隐式c prefix scope 这不是有效的代码 但表达了我需要的内容 c prefix inferImplicitValue 我目前正在使用一个简单的实
  • 如何在 Scala 用户定义注释中使用命名参数?

    在下面的代码中 我能够获得第一个注释对象 Publishable 但不能获得第二个 第二个使用命名参数 它转换为 x 2 x 3 x 1 作为 AST 中的参数 我该如何正确地做到这一点 class Publishable val path
  • 将类型信息传递给 Scala 中的函数

    我有对 json 对象执行一些常见操作的代码 即提取 所以我想创建一个通用函数 它接受哪个类的类型参数 代码如下所示 def getMessageType T json JValue Either GenericError T try Ri
  • Scalaz 状态 monad 示例

    我还没有看到很多 scalaz 状态单子的例子 有这个例子 http scalaz github com scalaz scalaz 2 9 1 6 0 2 doc sxr scalaz example ExampleState scala

随机推荐