4

所以这是我的困境:我有一个域模型,在 scala 中有一堆案例类,例如UserOrganization. 在我的数据访问层(dao、存储库等)中,我使用 astyanax(来自 netflix 的 java 库),它是实体持久化器,用于将对象保存到 cassandra 列族。

这是我的 cassandra/astyanax 支持的 DAO 的一些示例代码(是的,我知道我需要做一些更 scala-ish 的事情,但我仍在学习 =))

getDeclaredAnnotations()在阅读了这个冗长的描述之后,我基本上是想看看为什么当 java 执行时参数列表中的带注释的 val 不起作用Field我不想回去重构所有东西,这样我就可以使用持久化使保存实体(即manager.put(entity))变得非常简单。如果我想继续使用案例类,以便可以使用更多不可变样式的 scala 和Lensscalaz,那么我将不得不更新 DAO 并手动执行所有持久化操作,这真的可以消磨时间。

所以,如果有人知道我没有看到的东西,请告诉我!提前感谢您花时间阅读本文。

场景 1 - 案例类

Astyanax 无法获取注释 @Id onval

@实体
case class Organization(@Id @Column(name = "id") override val id: Option[UUID] = None,
                        @Column(name = "created_on") 覆盖 val createdOn: Option[Date] = None,
                        @Column(name = "modified_on") 覆盖 val modifiedOn: Option[Date] = None,
                        @Column(name = "name") 名称:选项 [字符串] = 无,
                        @Column(name = "is_paid_account") isPaidAccount: Boolean = false) 扩展 IdBaseEntity[UUID](id, createdOn, modifiedOn)

场景 2 - 有伴生对象的类或没有伴生对象的类

Astyanax 无法获取 @Id 注释val

@实体
类组织(@Id @Column(name = "id") 覆盖有效 id: Option[UUID] = None,
                       @Column(name = "created_on") 覆盖 val createdOn: Option[Date] = None,
                       @Column(name = "modified_on") 覆盖 val modifiedOn: Option[Date] = None,
                       @Column(name = "name") 名称:选项 [字符串] = 无,
                       @Column(name = "is_paid_account") isPaidAccount: Boolean = false) 扩展 IdBaseEntity[UUID](id, createdOn, modifiedOn)

对象组织{
  def apply(id: Option[UUID] = None,
            createdOn: 选项 [日期] = 无,
            修改时间:选项 [日期] = 无,
            名称:选项 [字符串] = 无,
            isPaidAccount: Boolean = false) = new Organization(id, createdOn, modifiedOn, name, isPaidAccount)
}

场景 3 - 在块内定义了 val 的案例类或类

这很好用,因为它theId被注释为@Id,但我不想这样做,因为IdBaseEntity已经定义了 andid val并且破坏了继承的整个目的并能够传递id给超类

@实体
case class Organization(@Id @Column(name = "id") override val id: Option[UUID] = None,
                        @Column(name = "created_on") 覆盖 val createdOn: Option[Date] = None,
                        @Column(name = "modified_on") 覆盖 val modifiedOn: Option[Date] = None,
                        @Column(name = "name") 名称:选项 [字符串] = 无,
                        @Column(name = "is_paid_account") isPaidAccount: Boolean = false) 扩展 IdBaseEntity[UUID](id, createdOn, modifiedOn) {
  @Id @Column(name = "id") val theId: Option[UUID] = id
}

数据访问部分

在经理中你会看到一个电话build()。Astyanax 检查传入的类,withEntityType()在本例中为classOf[Organization]

我的每个场景都失败了,除了#3,当我在类块内声明了一个 val 而不是案例类或带有伴随对象的常规类/常规类的参数列表时。Astyanax 说该类的已知成员带有注释,@Id因此它会引发异常。在我进一步挖掘之前,我想我会向社区询问注释 scala 类并将其发送到进行反射的 java 库的细微差别。来源没什么特别的。实际上,这是失败的相关行:https ://github.com/Netflix/astyanax/blob/master/astyanax-entity-mapper/src/main/java/com/netflix/astyanax/entitystore/EntityMapper.java #L89-120

类 CassandraOrganizationDAO 扩展 BaseCassandraDAO[Organization, UUID](Astyanax.context) 与 OrganizationDAO {
  val ColumnFamilyOrganizations: ColumnFamily[UUID, String] = new ColumnFamily[UUID, String](
    “组织”,
    TimeUUIDSerializer.get(),
    StringSerializer.get(),
    ByteBufferSerializer.get())

  val ColumnFamilyOrganizationMembers: ColumnFamily[UUID, UUID] = new ColumnFamily[UUID, UUID](
    “组织成员”,
    TimeUUIDSerializer.get(),
    TimeUUIDSerializer.get(),
    DateSerializer.get())

  val manager: EntityManager[Organization, UUID] = new DefaultEntityManager.Builder[Organization, UUID]()
    .withEntityType(classOf[组织])
    .withKeyspace(getKeyspace())
    .withColumnFamily(ColumnFamilyOrganizations)
    。建造()

 // 类的其余部分被省略
}
4

2 回答 2

5

我遇到了一个类似的问题,我的注释从未在构造函数的字段中考虑在内。事实上,我使用了 SpringData,并且不可能直接@Indexed在字段上映射注释(如 )。

要在案例类的构造函数中启用注释,您应该首先创建这种类:

object FixedScalaAnnotations {
  type Id = com.packagecontainingid.Id @field //replace by the right package
  type Column = com.packagecontainingcolumn.Column @field
}

然后在你的案例类中导入它并使用它而不是原来的:

import FixedScalaAnnotations._

@Entity
case class Organization(@Id @Column(name = "id") override val id: Option[UUID] = None,
                        @Column(name = "created_on") override val createdOn: Option[Date] = None,
                        @Column(name = "modified_on") override val modifiedOn: Option[Date] = None,
                        @Column(name = "name") name: Option[String] = None,
                        @Column(name = "is_paid_account") isPaidAccount: Boolean = false) extends IdBaseEntity[UUID](id, createdOn, modifiedOn)

确保不使用原始包装。

这里有一篇关于 JPA 的相关文章:http: //blog.fakod.eu/2010/07/14/constructor-arguments-with-jpa-annotations/

于 2013-05-02T23:11:02.073 回答
1

@Mik378 在处理 JPA 注释方面提供了很大帮助,这似乎适用于使用 Hibernate 之类的东西的人。但是,就我而言,我使用的是 Astyanax,它可能只是它的细微差别之一,所以鉴于我从上面的 @Mike378 学到的知识,我将发布对我有用的解决方案。

IdBaseEntity重要提示:当是抽象类或类时,我什么也做不了

解决方案:我不得不让 IdBaseEntity 成为一个特征,一切都很好

这是层次结构

BaseEntity.scala

import java.util.Date

trait BaseEntity {
  val createdOn: Option[Date] = None
  val modifiedOn: Option[Date] = None
}

IdBaseEntity.scala

trait IdBaseEntity[T <: java.io.Serializable] extends BaseEntity {
  val id: Option[T] = None
}

FixedScalaAnnotations.scala

import scala.annotation.meta.field

object FixedScalaAnnotations {
  type Id = javax.persistence.Id @field
  type Column = javax.persistence.Column @field
}

Organization.scala

import java.util.{Date, UUID}
import FixedScalaAnnotations._
import javax.persistence.Entity

@Entity
case class Organization(@Id @Column(name = "id") override val id: Option[UUID] = None,
                        @Column(name = "created_on") override val createdOn: Option[Date] = None,
                        @Column(name = "modified_on") override val modifiedOn: Option[Date] = None,
                        @Column(name = "name") name: Option[String] = None,
                        @Column(name = "is_paid_account") isPaidAccount: Boolean = false) extends IdBaseEntity[UUID]
于 2013-05-03T21:24:28.313 回答