我一直在为scala中的类型关系以及如何有效地使用它们而奋斗。目前,我正试图了解如何使用它们只编辑蒙古族集合中的某些字段。这意味着将只包含这些字段的特定对象传递给(在阅读关于差异之后)我认为可以这样做的方法:
abstract class DocClass
case class DocPart1(oId: Option[BSONObjectID], name: String, other: String) extends DocClass
case class DocPart2(city: String, country: String) extends DocClass
使用调用更通用方法的方法,如:
def updateMultipleFields(oId: Option[BSONObjectID], dataModel: DocClass): Future[Result] = serviceClientDb.updateFields[T](collectionName, dataModel, oId)
// updateFields updates the collection by passing *dataModel* into the collection, i.e. Json.obj("$set" -> dataModel)
所以dataModel
可以是DocPart1
或DocPart2
对象。我渴望不要在updateMultipleFields
上使用类型参数(正如这个有趣的文章可能建议的那样),因为这将导致我在项目中的其他文件中将这些类型参数传递给这个方法时会遇到进一步的问题。我这样做是为了遵守DRY,并为了维护高效的数据库操作。
我绕着这个转了圈--有人能给我一点启示吗?
在@SerGr的评论之后编辑
所以说得很清楚,我使用的是Play/Scala/ReactiveMongo (作为记录在这里),我有一个包含很多字段的MongoDB集合。
case class Doc(oId: Option[BSONObjectID], name: String, city: String, country: String, city: String, continent: String, region: String, region: String, latitude: Long, longitude: Long)
要创建一个新文档,我已经将Doc
(上面)自动映射到集合结构(在Play -像这样中),并创建了一个表单(用于插入/更新集合)--所有操作都很好!
但是在编辑文档时,我只想更新一些字段(这样所有字段都不会更新)。因此,我创建了多个case classes
,将这些字段划分为较小的模型(如DocPart1
&DocPart2
的示例),并将表单数据映射到一个。这导致我将这些参数作为参数传递给updateMultipleFields
方法,如上面所示。我希望这样做更有意义。
发布于 2017-11-23 12:41:59
我不确定我是否正确地理解了你的需要。这里还有一些可能是它的代码。假设我们的FullDoc
类定义为:
case class FullDoc(_id: Option[BSONObjectID], name: String, other: String)
我们有两个部分更新,定义为:
sealed trait BaseDocPart
case class DocPart1(name: String) extends BaseDocPart
case class DocPart2(other: String) extends BaseDocPart
此外,假设我们有一个访问我们蒙古族藏品的人:
def docCollection: Future[JSONCollection] = ...
所以,如果我理解你的要求,你需要的是这样的东西:
def update[T <: BaseDocPart](oId: BSONObjectID, docPart: T)(implicit format: OFormat[T]) = {
docCollection.flatMap(_.update(BSONDocument("_id" -> oId),
JsObject(Seq("$set" -> Json.toJson(docPart)))))
}
本质上,主要的诀窍是使用通用的T <: BaseDocPart
并传递implicit format: OFormat[T]
,这样即使在类型擦除之后,我们也可以将BaseDocPart
的特定子级转换为JSON。
下面是一些额外的测试代码(我在控制台应用程序中使用了这些代码)
implicit val fullFormat = Json.format[FullDoc]
implicit val part1Format = Json.format[DocPart1]
implicit val part2Format = Json.format[DocPart2]
def insert(id: Int) = {
val fullDoc = FullDoc(None, s"fullDoc_$id", s"other_$id")
val insF: Future[WriteResult] = docCollection.flatMap(_.insert(fullDoc))
val insRes = Await.result(insF, 2 seconds)
println(s"insRes = $insRes")
}
def loadAndPrintAll() = {
val readF = docCollection.flatMap(_.find(Json.obj()).cursor[FullDoc](ReadPreference.primaryPreferred).collect(100, Cursor.FailOnError[Vector[FullDoc]]()))
val readRes = Await.result(readF, 2 seconds)
println(s"readRes =\n${readRes.mkString("\n")}")
}
def loadRandomDocument(): FullDoc = {
val readF = docCollection.flatMap(_.find(Json.obj()).cursor[FullDoc](ReadPreference.primaryPreferred).collect(100, Cursor.FailOnError[Vector[FullDoc]]()))
val readRes = Await.result(readF, 2 seconds)
readRes(Random.nextInt(readRes.length))
}
def updateWrapper[T <: BaseDocPart](oId: BSONObjectID, docPart: T)(implicit writer: OFormat[T]) = {
val updateRes = Await.result(update(oId, docPart), 2 seconds)
println(s"updateRes = $updateRes")
}
// pre-fill with some data
insert(1)
insert(2)
insert(3)
insert(4)
val newId: Int = ((System.currentTimeMillis() - 1511464148000L) / 100).toInt
println(s"newId = $newId")
val doc21: FullDoc = loadRandomDocument()
println(s"doc21 = $doc21")
updateWrapper(doc21._id.get, DocPart1(s"p1_modified_$newId"))
val doc22: FullDoc = loadRandomDocument()
println(s"doc22 = $doc22")
updateWrapper(doc22._id.get, DocPart2(s"p2_modified_$newId"))
loadAndPrintAll()
https://stackoverflow.com/questions/47419932
复制相似问题