所以这是我的困境:我有一个领域模型,在scala中有一堆case类,如User
和Organization
。在我的数据访问层(dao, repository等)中,我使用astyanax(来自netflix的java库),它的实体持久性将对象保存到cassandra列族。
这是我的cassandra/astyanax支持的dao的一些示例代码(是的,我知道我需要做一些更scalish的事情,但我仍在学习=)
读完这篇冗长的描述后,我基本上想看看为什么在参数列表中带注释的值在java对Field
做getDeclaredAnnotations()
时不起作用,我讨厌不得不回去重构一切,这样我就可以使用persister,这使得保存实体(即manager.put(entity)
)变得非常简单。如果我想继续使用case类,这样我就可以使用更具不可变风格的scala和来自scalaz的Lens
,那么我就必须更新DAO并手动执行所有的持久化操作,这真的很浪费时间。
场景1 -案例类
Astyanax无法拾取val
上的注释@Id
<>以前@ entitycase 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 modifieddon: Option[Date] = None,@Column(name = "name") name: Option[String] = None,@Column(name = "is_paid_account") isPaidAccount: Boolean = false) extends IdBaseEntity[UUID](id, createdOn, modifieldon)场景2 -类有伴侣对象或没有伴侣对象
Astyanax无法拾取val
上的@Id注释
<>以前@ entityclass 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 modifieddon: Option[Date] = None,@Column(name = "name") name: Option[String] = None,@Column(name = "is_paid_account") isPaidAccount: Boolean = false) extends IdBaseEntity[UUID](id, createdOn, modifieldon)对象组织{def apply(id: Option[UUID] = None,createdOn: Option[Date] = None,modifieldon: Option[Date] = None,name: Option[String] = None,isPaidAccount: Boolean = false) = new Organization(id, createdOn, modifieldon, name, isPaidAccount)}场景3 -在block中定义val的Case类或类
这工作得很好,因为它拾取theId
作为与@Id
注释,但我不想这样做,因为IdBaseEntity
已经定义和id val
,并击败继承的整个目的,并能够将id
传递给超类
<>以前@ entitycase 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 modifieddon: Option[Date] = None,@Column(name = "name") name: Option[String] = None,@Column(name = "is_paid_account") isPaidAccount: Boolean = false) extends IdBaseEntity[UUID](id, createdOn, modifieldon) {@Id @Column(name = "id") val theId: Option[UUID] = id}数据访问部分
在管理器中,您将看到对build()
的调用。Astyanax检查传递给withEntityType()
的类,在本例中是classOf[Organization]
当我在类块中声明了一个val而不是case类的参数列表或带伴体对象的常规类/常规类时,除了#3之外,我的每个场景都失败了。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]("organization_members",TimeUUIDSerializer.get (),TimeUUIDSerializer.get (),DateSerializer.get ())val manager: EntityManager[Organization, UUID] = new DefaultEntityManager。Builder(组织、UUID) ().withEntityType(名为[机构]classOf).withKeyspace (getKeyspace ()).withColumnFamily (ColumnFamilyOrganizations).build ()//类的其余部分被省略}
我遇到了一个类似的问题,在构造函数的字段中从来没有考虑到我的注释。实际上,我使用了SpringData,并且不可能直接在字段上映射注释(如@Indexed
)。
object FixedScalaAnnotations {
type Id = com.packagecontainingid.Id @field //replace by the right package
type Column = com.packagecontainingcolumn.Column @field
}
然后将它导入到case类中并使用它来代替原来的:
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/
@Mik378在处理JPA注释方面提供了很大的帮助,这似乎适用于使用Hibernate之类的东西的人。然而,在我的情况下,我使用的是Astyanax,这可能只是它的一个细微差别,所以我将根据我从上面的@Mike378中学到的东西发布适合我的解决方案。
重要:当IdBaseEntity
是一个抽象类或类时,我无法让任何东西工作。
解决方案:我不得不让IdBaseEntity一个trait代替,一切都工作得很好
下面是层次结构
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]