任意的实体Bean定义,如果想通过扫描的方式让框架进行序列化支持,均需要在源代码类上作些标记。
例如定义一个User实体
@Entity
class User{
@Id
@GeneratedValue(strategy=SEQUENCE, generator="seq_users")
var id:Integer=_
@Embedded
var name:Name=_
}
@Embeddable
class Name{
var first:String=_
var last:String=_
}
或者
class User extends LongId{
var name:Name=_
}
class Name{
var first:String=_
var last:String=_
}
如果User类复杂度上升,模型中又增加了Role,Member等等,代码如下:
class User(var id: java.lang.Long) extends Entity[java.lang.Long] {
def this() = this(0)
var name = new Name
var roleSet: java.util.Set[Role] = new java.util.HashSet[Role]
var age: Option[Int] = None
var money: Short = _
var properties: collection.mutable.Map[String, String] = _
var occupy: WeekState = _
var weekday: WeekDay = _
var createdOn: java.sql.Date = _
var role: Role = _
var roleList: collection.mutable.Buffer[Role] = new collection.mutable.ListBuffer[Role]
var member: Member = _
var skills: collection.mutable.Map[SkillType, Skill] = _
}
class SkillType extends LongId
class Skill extends LongId{
var skillType:SkillType=_
}
class Name extends Component {
var first: String = _
var last: String = _
}
class Member extends Component {
@scala.beans.BeanProperty
var user: User = _
var granter: Role = _
var admin: Boolean = _
var roles: collection.mutable.Set[Role] = _
}
按照JPA的规范,实体的定义应该加上@Entity注解,嵌入类应该加上@Embeddable注解。其他各类属性、以及实体之间的关系、生命周期等等均需要在属性或者方法上加以注解说明。由于Java支持嵌套注解,很多描述相当强大,同时也比较复杂。
可在Scala中使用JPA,却困难重重。
上述代码中包含了以下情况:
这些情况如果使用传统的hibernate的映射文件,大致需要写法:
<class name="org.beangle.data.jpa.model.User" >
<id name="id" unsaved-value="0" type="long" >
<generator class="native"/>
</id>
<component name="name" class="Name">
<property name="first" length="50" column="first_name" not-null="true"/>
<property name="last" length="50" not-null="true"/>
</component>
<set name="roleSet" table="users_role_set">
<key column="user_id"/>
<many-to-many entity-name="org.beangle.data.jpa.model.Role" column="role_id"/>
</set>
<list name="roleList" collection-type="seq" table="users_roles_list">
<key column="user_id"/>
<list-index column="idx"/>
<many-to-many entity-name="org.beangle.data.jpa.model.Role" column="role_id"/>
</list>
<property name="age" type="int?"/>
<map name="properties" cascade="all" collection-type="map" table="users_props">
<key column="user_id"/>
<map-key column="name" type="string"/>
<element column="value" type="string"/>
</map>
<component name="member" class="Member">
<parent name="user"/>
<many-to-one name="granter"/>
<property name="admin" not-null="true"/>
<set name="roles" table="users_roles" collection-type="set">
<key column="user_id"/>
<many-to-many entity-name="org.beangle.data.jpa.model.Role" column="role_id"/>
</set>
</component>
<property name="occupy" type="weekstate"/>
<property name="createdOn"/>
<map name="skills" cascade="all" collection-type="map">
<key column="user_id"/>
<map-key-many-to-many class="org.beangle.data.jpa.model.SkillType" column="skill_type_id"/>
<many-to-many class="org.beangle.data.jpa.model.Skill" column="skill_id"/>
</map>
</class>
<class name="org.beangle.data.jpa.model.Role" >
<id name="id" unsaved-value="0" type="integer">
<generator class="assigned"/>
</id>
<property name="name" length="50" unique="true"/>
</class>
<class name="org.beangle.data.jpa.model.Skill" table="skill_list" >
<id name="id" unsaved-value="0" type="integer">
<generator class="assigned"/>
</id>
<many-to-one name="skillType"/>
<property name="name"/>
</class>
<class name="org.beangle.data.jpa.model.SkillType" >
<id name="id" unsaved-value="0" type="integer">
<generator class="assigned"/>
</id>
<property name="name"/>
</class>
因此如果在scala中使用注解,支持全方位的映射功能,没有实现的办法。可以采用Beangle中基于代码的配置方法。
object TestMapping1 extends Mapping {
def binding(): Unit = {
defaultIdGenerator("assigned")
bind[Coded].on(c => declare(c.code is (notnull, length(20))))
bind[User].on(e => declare(
e.name.first is (unique, column("first_name")),
e.name.first & e.name.last & e.createdOn are notnull,
e.roleList is (ordered, table("users_roles_list")),
e.properties is (table("users_props"), eleColumn("value2"), eleLength(200)))).generator("native")
bind[SkillType]
bind[Skill].table("skill_list")
bind[Role].on(r => declare(
r.name is (notnull, length(112), unique),
r.children is (depends("parent"), cacheable)))
}
}
最后在META-INF/beangle/orm.xml进行注册
<?xml version="1.0" encoding="UTF-8"?>
<orm>
<mapping class="org.beangle.data.jpa.hibernate.TestMapping1"/>
</orm>
以User为例说明如何注册类型:
bind[User]
这样声明后,User的原来在xml使用property,many-to-one,many-to-many(list,set,map)的属性是自动配置的,没有其他要求可以不必写明。 需要特殊要求的再进行说明。
声明ID产生器以及缓存等:
bind[User].generator("sequence").cacheable()
说明属性非空:
bind[User].on(e => declare(
e.createdOn is notnull
))
说明属性的多个方面:
bind[User].on(e => declare(
e.name.first is (unique, column("first_name"))
))
多个属性打包说明:
bind[User].on(e => declare(
e.name.first & e.name.last & e.createdOn are notnull
))
增加集合的排序字段:
bind[User].on(e => declare(
e.roleList is ordered
))
声明一对多:
bind[Role].on(e => declare(
r.children is one2many("parent").cascade("all",true)
))
如果属于具有依赖关系的主从的关系:
bind[Role].on(e => declare(
r.children is depends("parent")
))
声明缓存区和策略:
defaultCache("test_cache_region", "read-write")
bind[A]
bind[B].cache("B_cache","ready_only")
// bind....
all.except(classOf[C],classOf[D],classOf[B]).cachable()
默认缓存区test_cache_region,本模块的所有类除了B、C、D之外所有的类都进行缓存。
扩展一个既定模块的类:
class ExtendRole(id: Integer) extends Role(id) {
var enName: String = _
def this() = this(0)
}
object TestMapping2 extends Mapping {
def binding(): Unit = {
//使用相同的Entity-Name,即可实现重置。Role的表中会增加en_name字段
bind[ExtendRole](classOf[Role].getName)
}
}
在META-INF/beangle/orm.xml进行增加注册
<?xml version="1.0" encoding="UTF-8"?>
<orm>
<mapping class="org.beangle.data.jpa.hibernate.TestMapping1"/>
<mapping class="org.beangle.data.jpa.hibernate.TestMapping2"/>
</orm>
映射一个接口或者超类:
bind[CodedEntity].on(c => declare(c.code is (length(22))))
CodedEntity的子类,其Code属性的长度为22.
自定义表名
bind[User].on(e => declare(
e.roleList is (ordered, table("users_roles_list"))
)).table("user_list")
配置Map
bind[User].on(e => declare(
e.properties is (table("users_props"), eleColumn("value2"), eleLength(200))
))
User中的properties属性中的value对应到列value2上,长度为200.
声明命名策略和schema划分
在META-INF/beangle/orm.xml进行增加注册
<?xml version="1.0" encoding="UTF-8"?>
<orm>
<mapping class="org.beangle.data.jpa.hibernate.TestMapping1"/>
<mapping class="org.beangle.data.jpa.hibernate.TestMapping2"/>
<naming>
<profile package = "org.beangle.data.jpa" pluralize="true" schema="jpa">
<profile package = "mapping" plau="true" prefix="mp_"/>
</profile>
<profile package = "org.beangle.data.jpa.dao" pluralize="true" schema="dao"/>
</naming>
</orm>
jpa模块会映射到jpa的schema上,其他的包各自映射自己的schema上。profile中支持嵌套描述子包的特征,子包继承父包的特征。 例如对应org.beangle.data.jpa.mapping的profile,其表前缀为mp_,schema仍为jpa.