我如何从抽象斯卡拉持久层领域层 [英] How do I abstract the domain layer from the persistence layer in Scala

查看:152
本文介绍了我如何从抽象斯卡拉持久层领域层的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:
我已经编辑标题,并添加该文本,以便更好地解释我努力实现:我试图创建从头开始一个新的应用程序,但不希望业务层了解的持久层,以同样的方式是不希望的业务层知道一个REST API层。下面是我想用一个持久层的一个例子。我在寻找好的建议与此即我需要设计/架构有助于业务逻辑和持久性逻辑之间划分清晰的职责整合。也许沿着编组和持久性的解组线概念反对域对象。

UPDATE: I've edited the title and added this text to better explain what I'm trying to achieve: I'm trying to create a new application from the ground up, but don't want the business layer to know about the persistence layer, in the same way one would not want the business layer to know about a REST API layer. Below is an example of a persistence layer that I would like to use. I'm looking for good advice on integrating with this i.e. I need help with the design/architecture to cleanly split the responsibilities between business logic and persistence logic. Maybe a concept along the line of marshalling and unmarshalling of persistence objects to domain objects.

这是一个漂亮的(又名ScalaQuery)<一个href=\"https://github.com/slick/slick/blob/01251edbc7f970f29f3a471d7eee27460e6846cf/src/test/scala/scala/slick/test/ql/ForeignKeyTest.scala#L177\">test例如的,这是你如何建立一个多对许多数据库的关系。这将创造3表:a,b和a_to_b,其中a_to_b保持在表a和b的行链路

From a SLICK (a.k.a. ScalaQuery) test example, this is how you create a many-to-many database relationship. This will create 3 tables: a, b and a_to_b, where a_to_b keeps links of rows in table a and b.

object A extends Table[(Int, String)]("a") {
  def id = column[Int]("id", O.PrimaryKey)
  def s = column[String]("s")
  def * = id ~ s
  def bs = AToB.filter(_.aId === id).flatMap(_.bFK)
}

object B extends Table[(Int, String)]("b") {
  def id = column[Int]("id", O.PrimaryKey)
  def s = column[String]("s")
  def * = id ~ s
  def as = AToB.filter(_.bId === id).flatMap(_.aFK)
}

object AToB extends Table[(Int, Int)]("a_to_b") {
  def aId = column[Int]("a")
  def bId = column[Int]("b")
  def * = aId ~ bId
  def aFK = foreignKey("a_fk", aId, A)(a => a.id)
  def bFK = foreignKey("b_fk", bId, B)(b => b.id)
}

(A.ddl ++ B.ddl ++ AToB.ddl).create
A.insertAll(1 -> "a", 2 -> "b", 3 -> "c")
B.insertAll(1 -> "x", 2 -> "y", 3 -> "z")
AToB.insertAll(1 -> 1, 1 -> 2, 2 -> 2, 2 -> 3)

val q1 = for {
  a <- A if a.id >= 2
  b <- a.bs
} yield (a.s, b.s)
q1.foreach(x => println(" "+x))
assertEquals(Set(("b","y"), ("b","z")), q1.list.toSet)

由于我的下次的一步,我想借此上一级(我还是想用光滑,但很好地把它包),为使用对象。因此,在伪code这将是巨大的做这样的事情:

As my next step, I would like to take this up one level (I still want to use SLICK but wrap it nicely), to working with objects. So in pseudo code it would be great to do something like:

objectOfTypeA.save()
objectOfTypeB.save()
linkAtoB.save(ojectOfTypeA, objectOfTypeB)

或者类似的东西。我有我的,我怎么可能在Java中解决这个想法,但我开始意识到,一些纯面向对象的语言我的面向对象的思想也开始令我失望。任何人都可以请给我一些指点至于如何在Scala中解决这个问题。

Or, something like that. I have my ideas on how I might approach this in Java, but I'm starting to realize that some of my object-oriented ideas from pure OO languages are starting to fail me. Can anyone please give me some pointers as to how approach this problem in Scala.

例如:我创建简单的对象只是包装或扩展表对象,然后包括这些(组成)到该管理它们的另一个类

For example: Do I create simple objects that just wrap or extend the table objects, and then include these (composition) into another class that manages them?

任何想法,指导,例如(请),这将有助于我更好地解决这个问题,作为一个设计师和codeR将大大AP preciated。

Any ideas, guidance, example (please), that will help me better approach this problem as a designer and coder will be greatly appreciated.

推荐答案

对于简单的持久要求一个好的解决方法是ActiveRecord的模式:的 http://en.wikipedia.org/wiki/Active_record_pattern 。这在Ruby和游戏中实现!框架1.2,你可以很容易地实现它在斯卡拉在独立的应用程序

A good solution for simple persistence requirements is the ActiveRecord pattern: http://en.wikipedia.org/wiki/Active_record_pattern . This is implemented in Ruby and in Play! framework 1.2, and you can easily implement it in Scala in a stand-alone application

的唯一要求是有一个单身DB或单服务来获取你所需要的DB的引用。我个人会去基于以下实现:

The only requirement is to have a singleton DB or a singleton service to get a reference to the DB you require. I personally would go for an implementation based on the following:


  • 的通用特性的ActiveRecord

  • 一个通用的类型类ActiveRecordHandler

开拓implicits的力量,你可以得到一个惊人的语法:

Exploiting the power of implicits, you could obtain an amazing syntax:

trait ActiveRecordHandler[T]{

  def save(t:T):T

  def delete[A<:Serializable](primaryKey:A):Option[T]

  def find(query:String):Traversable[T]
}

object ActiveRecordHandler {
  // Note that an implicit val inside an object with the same name as the trait 
  // is  one of the way to have the implicit in scope.
  implicit val myClassHandler = new ActiveRecordHandler[MyClass] {

    def save(myClass:MyClass) = myClass

    def delete[A <: Serializable](primaryKey: A) = None

    def find(query: String) = List(MyClass("hello"),MyClass("goodbye"))
  }
}

trait ActiveRecord[RecordType] {
  self:RecordType=>


  def save(implicit activeRecordHandler:ActiveRecordHandler[RecordType]):RecordType = activeRecordHandler.save(this)

  def delete[A<:Serializable](primaryKey:A)(implicit activeRecordHandler:ActiveRecordHandler[RecordType]):Option[RecordType] = activeRecordHandler.delete(primaryKey)
}

case class MyClass(name:String) extends ActiveRecord[MyClass] 

object MyClass {
  def main(args:Array[String]) = {
    MyClass("10").save
  }
}

通过这样的解决方案,你只需要你的类扩展ActiveRecord的[T],并有一个隐含的ActiveRecordHandler [T]来处理这个问题。

With such a solution, you only need your class to extends ActiveRecord[T] and have an implicit ActiveRecordHandler[T] to handle this.

其实也有一个实现: https://github.com/aselab/scala-activerecord这是基于类似的想法,但是,而不是制造具有抽象类型ActiveRecord的,它声明了一个通用的同伴对象。

There is actually also an implementation: https://github.com/aselab/scala-activerecord which is based on similar idea, but instead of making the ActiveRecord having an abstract type, it declares a generic companion object.

在ActiveRecord的模式一般但很重要的评论是,它有助于满足持久性方面的简单要求,但不能有更多要求的处理:比如当你想坚持在同一事务中的多个对象。

A general but very important comment on the ActiveRecord pattern is that it helps meet simple requirements in terms of persistence, but cannot deal with more complex requirements: for example is when you want to persist multiple objects under the same transaction.

如果您的应用程序需要更复杂的持久性逻辑,最好的办法是引入一个持久性服务,只公开了一组有限的功能,客户端类,例如:

If your application requires more complex persistence logic, the best approach is to introduce a persistence service which exposes only a limited set of functions to the client classes, for example

DEF坚持(objectsofTypeA:Traversable的[A],objectsOfTypeB:Traversable的[B])

另外请注意,根据您的应用程序的复杂性,您可能希望以不同的方式公开此逻辑:

Please also note that according to your application complexity, you might want to expose this logic in different fashions:


  • 作为的情况下单对象,你的应用程序很简单,你不希望你的持久性逻辑可以插入

  • 通过它作为一种为应用程序上下文,让你在启动应用程序就可以决定你要使用的持久性逻辑的单独的对象。

  • 带有某种查询服务模式,如果你的应用是分布式的。

这篇关于我如何从抽象斯卡拉持久层领域层的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆