【问题标题】:Scala Generic Repository Class For Reactive Mongo Repository(alpakka) - Needed Class Found T用于响应式 Mongo 存储库(alpakka)的 Scala 通用存储库类 - 找到需要的类 T
【发布时间】:2022-01-27 11:21:02
【问题描述】:

我正在尝试在 Scala 中创建一个通用类,这样我就可以为不同的集合创建一个存储库,而无需重复自己。

问题是,如果我将其作为通用类(如本例中),我会在这一行遇到问题:

val codecRegistry = fromRegistries(fromProviders(classOf[T]), DEFAULT_CODEC_REGISTRY)

预期类但找到 [T]

但是,如果我在所有代码中为任何其他类(比如说用户)更改 T,它就可以工作。

这是我的课:

    package persistence.repository.impl
    import akka.stream.Materializer
    import akka.stream.alpakka.mongodb.scaladsl.{MongoSink, MongoSource}
    import akka.stream.scaladsl.{Sink, Source}
    import akka.{Done, NotUsed}
    import com.mongodb.reactivestreams.client.MongoClients
    import constants.MongoConstants._
    import org.bson.codecs.configuration.CodecRegistries.{fromProviders, fromRegistries}
    import org.mongodb.scala.MongoClient.DEFAULT_CODEC_REGISTRY
    import org.mongodb.scala.bson.codecs.Macros._
    import org.mongodb.scala.model.Filters
    import persistence.entity.{ProductItem}
    import persistence.repository.Repository
     
    import scala.concurrent.{ExecutionContext, Future}
    class UserMongoDatabase[T](implicit materializer: Materializer,
                            executionContext: ExecutionContext)
      extends Repository[T] {
      val codecRegistry = fromRegistries(fromProviders(classOf[T]), DEFAULT_CODEC_REGISTRY)
      val client = MongoClients.create(HOST)
      val db = client.getDatabase(DATABASE)
      val requestedCollection = db
        .getCollection(USER_COLLECTION, classOf[T])
        .withCodecRegistry(codecRegistry)
      val source: Source[T, NotUsed] =
        MongoSource(requestedCollection.find(classOf[T]))
      val rows: Future[Seq[T]] = source.runWith(Sink.seq)
     
      override def getAll: Future[Seq[T]] = rows
     
      override def getById(id: AnyVal): Future[Option[T]] = rows.map {
        list =>
          list.filter {
            user => user.asInstanceOf[ {def _id: AnyVal}]._id == id
          }.headOption
      }
     
      override def getByEmail(email: String): Future[Option[T]] = rows.map {
        list =>
          list.filter {
            user => user.asInstanceOf[ {def email: AnyVal}].email == email
          }.headOption
      }
     
      override def save(obj: T): Future[T] = {
        val source = Source.single(obj)
        source.runWith(MongoSink.insertOne(requestedCollection)).map(_ => obj)
      }
     
      override def delete(id: AnyVal): Future[Done] = {
        val source = Source.single(id).map(i => Filters.eq("_id", id))
        source.runWith(MongoSink.deleteOne(requestedCollection))
      }
    }

这是我的存储库特征:

包persistence.repository

import akka.Done

import scala.concurrent.Future

    trait Repository[T]{
      def getAll: Future[Seq[T]]
      def getById(id: AnyVal): Future[Option[T]]
      def save(user: T): Future[T]
      def delete(id: AnyVal): Future[Done]
      def getByEmail(email:String): Future[Option[T]]
    }

【问题讨论】:

  • 你不能得到一个任意类型的类T你可能宁愿为T请求一个隐式ClassTag并用它来得到它的runtimeClass

标签: scala generics akka alpakka


【解决方案1】:

正如 cmets 中所说,这是在 Scala 中使用 ClassTag 的完美示例。它允许保留泛型/参数化类的实际类。

class DefaultMongoDatabase[T](implicit ..., ct: ClassTag[T])
  extends Repository[T] {
  val codecRegistry = fromRegistries(fromProviders(ev.runtimeClass), ...)

(如果需要,您可以在 trait 中移动 classtag 逻辑。)

【讨论】:

    猜你喜欢
    • 2020-01-24
    • 2011-07-03
    • 2016-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多