Entity 与 EntityData
- Entity 作成(在 v3 环境中新规,然后拷贝到 v4)
- 类注解
- 变量注解
- text
- 枚举
- timestamp
- date
- time
- bigserial
- bigint
- integer
- varchar
- numeric
- boolean
- uuid
- duration
- ManyToOne
- OneToMany
- addToStringFields
- 配置文件增加 entity 路径(v3 和 v4)
- 调用脚本生成 SQL 文 - EntityLifecycle 作成
- EntityLifecycleImpl 作成
- EducationInstitute 与 EducationCenter
- 问题
- V4
- V3
- newInstance 和 convertToValue 的区别?
Entity 与 EntityData
entity
Entity 作成(在 v3 环境中新规,然后拷贝到 v4)
⚡ C:\gf4\其他\代码\entity 作成
[entity作成](file:///C:%5Cgf4%5C其他%5C代码%5Centity作成)
类注解
❗唯一键只有一个字段时,可以写成变量注解,无需写成类注解
// 唯一键有多个字段
@Entity
@Table(name = "groupware_message_recipient", schema = PersistenceConstants.DEFAULT_SCHEMA, uniqueConstraints = {
@UniqueConstraint(columnNames = { "groupware_message_entityid", "destination_user_entityid" }),
@UniqueConstraint(columnNames = { "groupware_message_entityid", "groupware_board_category_entityid" }) })
// 唯一键只有一个字段
@Column(name = "center_id", nullable = false, unique = true)
private String centerId;
变量注解
- 通用:@Column(name = "condition_keywords", nullable = false)
- 数据库字段需要特别定制时:使用 columnDefinition 属性,正常无需使用。
- 字段需要自定长度时,使用 length 属性。正常无需使用,按照默认的就行。
@Basic(optional = false):用于指定实体属性是否为必需的(非可选)。optional = false表示这个属性在持久化时是必需的,不能为null。通常情况下,如果数据库表中对应的列不允许为null,只需要使用@Column(nullable = false)即可。但如果你想明确地强调这个属性在 JPA 实体中也是必需的(非可选),你可以使用@Basic(optional = false)。
@Column(nullable = false, name = "id", columnDefinition = "numeric(8)", length = 255)
@Basic(optional = false)
private long id;
| 式样书变量类型 | Java 代码类型 | 特定注解 | 数据库类型 (default) | 备注 |
|---|---|---|---|---|
| text | String | @Lob | text | |
| 枚举 | 枚举 | @Enumerated(EnumType.STRING) | varchar(255) | |
| timestamp | LocalDateTime or Date | @Temporal(TemporalType.TIMESTAMP) | timestamp | |
| date | LocalDate or Date | @Temporal(TemporalType.DATE) | date | |
| bigserial | Long | 无 | bigserial | |
| bigint | long | 无 | int8 | |
| integer | int or Integer | 无 | int4 | |
| varchar、character | String | 无 | varchar(255) | |
| numeric | BigDecimal | 无 | numeric | |
| 关联的其他表(bigint) | entity | ManyToOne OneToMany | int8 | |
| 特殊枚举 | PrefectureCode | @Enumerated(EnumType.ORDINAL) | int2 | 参照 PrefectureCode 貌似时将枚举型变成了顺序数字 |
| time | Date or LocalDate | @Temporal(TemporalType.TIME) | time | 14:00:00 |
| float | double or Double | 无 | float8 | |
| Boolean | Boolean or boolean | 无 | bool | |
| UUID | UUID | @Column(name = "student_uuid", columnDefinition = "uuid") @Convert("uuidConverter") |
uuid |
text
/**
* itemLabel
*/
@Column(name = "item_label", nullable = false)
@Lob
private String itemLabel;
枚举
/**
* ConditionDistinguish
*/
@Column(name = "condition_distinguish", nullable = false)
@Enumerated(EnumType.STRING)
private ConditionDistinguish conditionDistinguish;
timestamp
/**
* LocalDateTime
*/
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "date_time", nullable = false)
private LocalDateTime dateTime;
or
private Date dateTime;
date
/**
* LocalDate
*/
@Temporal(TemporalType.DATE)
@Column(name = "date", nullable = false)
private LocalDate date;
or
private Date date;
time
/**
* time
*/
@Temporal(TemporalType.TIME)
@Column(name = "time", nullable = false)
private LocalDate time;
or
private Date time;
bigserial
/**
* entityId
*/
@Column(name = "entity_id", nullable = false)
private Long entityId;
bigint
/**
* entityId
*/
@Column(name = "entity_id", nullable = false)
private long entityId;
integer
/**
* entityId
*/
@Column(name = "entity_id", nullable = false)
private int entityId;
varchar、character
/**
* entityId
*/
@Column(name = "entity_id", nullable = false, length = 255)
private String entityId;
numeric
/**
* entityId
*/
@Column(name = "entity_id", nullable = false)
private BigDecimal entityId;
boolean
/**
* bool
*/
@Column(name = "bool", nullable = false)
private Boolean bool;
or
private boolean bool;
uuid
- 类上面要加上如下注解,并使用如下 2 个 jar:
import org.eclipse.persistence.annotations.Convert;
import org.eclipse.persistence.annotations.Converter;
@Converter(name = "uuidConverter", converterClass = UUIDConverter.class)
public class Student extends Person {
}
/**
* uuid
*/
@Column(name = "student_uuid", columnDefinition = "uuid")
@Convert("uuidConverter")
private UUID studentUuid;
duration
/**
* 結果_解答時間
*/
@Column(name = "result_duration", columnDefinition = "integer")
private Duration resultDuration;
ManyToOne
Summary:JPA,关于多对一的属性,是否需要加 JoinColumn 关联表字段的总结:
-
如果不加 JoinColumn,关联表字段。调用脚本生成的 sql,生成的字段名,是【entity 属性名_entityid】
例如:sibling


-
如果,表字段名不是【entity 属性名_entityid】,则必须加 JoinColumn,否则 jpa 不能将 entity 的属性与表字段进行映射关联。
例如:Guardian


@ManyToOne(cascade = { CascadeType.DETACH }, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "observation_record_entityid", nullable = false)
private ObservationRecord observationRecord;
/**
* <p>
* プロパティ<code>observationRecord</code>の値を取得する。
* </p>
*
* @return プロパティ<code>observationRecord</code>の値
*/
@ReplicatorMapping(skip = true)
public ObservationRecord getObservationRecord() {
return getObservationRecord_internal();
}
/**
* <p>
* プロパティ<code>observationRecord</code>の値を設定する。
* </p>
*
* @param observationRecord プロパティ<code>observationRecord</code>に設定する値
*/
public void setObservationRecord(final ObservationRecord observationRecord) {
final OneToManySupport<ObservationRecord, ObservationRecordCoordination> oneToManySupport = RelationSupportFactory.getInstance().getOneToManySupport(ObservationRecord.class, "coordinationList",
ObservationRecordCoordination.class, "observationRecord");
oneToManySupport.doSetOneSide(this, observationRecord);
}
private ObservationRecord getObservationRecord_internal() {
return observationRecord;
}
@SuppressWarnings("unused")
private void setObservationRecord_internal(final ObservationRecord observationRecord) {
this.observationRecord = observationRecord;
}
OneToMany
@OneToMany(mappedBy = "observationRecord", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private List<ObservationRecordCoordination> coordinationList;
/**
* <p>
* プロパティ<code>coordinationList</code>の値を取得する。
* </p>
*
* @return プロパティ<code>coordinationList</code>の値
*/
public List<ObservationRecordCoordination> getCoordinationList() {
final OneToManySupport<ObservationRecord, ObservationRecordCoordination> oneToManySupport = RelationSupportFactory.getInstance().getOneToManySupport(ObservationRecord.class, "coordinationList",
ObservationRecordCoordination.class, "observationRecord");
return oneToManySupport.doGetManySideList(this);
}
/**
* <p>
* プロパティ<code>coordinationList</code>の値を設定する。
* </p>
*
* @param coordinationList プロパティ<code>coordinationList</code>に設定する値
*/
public void setCoordinationList(final List<ObservationRecordCoordination> coordinationList) {
final OneToManySupport<ObservationRecord, ObservationRecordCoordination> oneToManySupport = RelationSupportFactory.getInstance().getOneToManySupport(ObservationRecord.class, "coordinationList",
ObservationRecordCoordination.class, "observationRecord");
oneToManySupport.doSetManySideCollection(this, coordinationList);
}
@ReplicatorMapping(skip = true)
private List<ObservationRecordCoordination> getCoordinationList_internal() {
return coordinationList;
}
@SuppressWarnings("unused")
private void setCoordinationList_internal(final List<ObservationRecordCoordination> coordinationList) {
this.coordinationList = coordinationList;
}
OneToOne
- TeachPlanSchool
@OneToOne(optional = false, fetch = FetchType.LAZY)
@JoinColumn(nullable = false)
private WeeklyPlanParticularLesson particularLesson;
- WeeklyPlanParticularLesson
@OneToOne(mappedBy = "particularLesson", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private TeachPlanSchool schoolPlan;
addToStringFields
@Override
protected void addToStringFields(final ToStringBuilder builder) {
super.addToStringFields(builder);
builder.append("answerRequestNo", getAnswerRequestNo());
builder.appendLazy("questionnaireItemRegionGroup");
builder.appendLazy("schoolMembership");
}
or
@Override
protected void addToStringFields(final ToStringBuilder builder) {
super.addToStringFields(builder);
builder.auto(this);
}
配置文件增加 entity 路径(v3 和 v4)
- devlib/schematoollib/persistence.xml —— 脚本生成 sql 文用到(新增的 entity 需要添加到里面,然后执行 sql 脚本)
- numata/tools/META-INF/persistence.xml —— 单体测试用到
persistence.xml
- V4
- tools/META-INF/persistence.xml:单体测试
- devlib/schematoollib/persistence.xml:??
- V3
- numata/tools/META-INF/persistence.xml:单体测试
- devlib/schematoollib/persistence.xml:生成 sql 文
- numata/bin/persistence.xml:??
调用脚本生成 SQL 文
-
对应 entity 的配置文件:devlib/schematoollib/persistence.xml
-
修改数据库:build.properties

-
脚本:build.xml - generateAddSchemaSql
-
ant 脚本执行前,先 build 一下
-
生成:out/packages/schemqSql/addSchema.sql
-
筛选出 addSchema.sql 中本次新增的 entity 的 sql 文。将 sql 文脚本放入对应位置 sql/verified/3.15.04。
EntityLifecycle 作成
public interface ReleaseMenuLifecycle extends Lifecycle<ReleaseMenu> {
ImmutableList<ReleaseMenu> findBy(C4v4MenuId menuId, CenterId centerId);
}
EntityLifecycleImpl 作成
public class ReleaseMenuLifecycleImpl extends AbstractManagementLifecycle<ReleaseMenu> implements ReleaseMenuLifecycle {
public ReleaseMenuLifecycleImpl(final LifecycleContext context) {
super(context);
}
@Override
public ImmutableList<ReleaseMenu> findBy(final C4v4MenuId menuId, final CenterId centerId) {
final QueryBuilderMulti<ReleaseMenu> builder = newMultipleResultQueryBuilder();
builder.add("select o from ReleaseMenu o where 1=1");
builder.add(" and o.centerId = :theCenterId ", centerId != null ? centerId.toString() : "", centerId != null);
builder.add(" and o.menuId = :theMenuId ", menuId, menuId != null);
return builder.getReadOnlyResult();
}
@Override
public Class<ReleaseMenu> getEntityType() {
return ReleaseMenu.class;
}
@Override
public ReleaseMenu newInstance() {
return new ReleaseMenu();
}
}
EducationInstitute 与 EducationCenter


问题
- #Work/question addToStringFields 方法有什么用?builder.auto(this); 有什么用?
- entity 中,get、set 方法是否可以使用 final 修饰符?
- 不需要
#总结 entity 双向关联时,OneToManySupport 的使用?
- #Work/question_delay @ReplicatorMapping(skip = true) 注解有啥用?定义双向关联时,是否必须加上?
- #Work/question_delay entityA 中设置了 manytoone 的关系,entityB 中一定需要设置 onetomany 的关系吗?
- 不一定需要设置,可以只由一方代码维护关系。只由一方维护时,不需要使用 OneToManySupport。entity 生成简单的 get 和 set 方法就行。
- 什么时候需要两方维护???
- #Work/question_delay 使用 OneToManySupport 的作用是什么???
- 关联的 2 个 entity,在双方同事维护时,需要使用 OneToManySupport。
entitydata
作成规则:
- 变量
1.
// 参照:
businessdata
// 参照:
entity 与 entitydata 转化(AbstractPersistenceOperationService)
V4
entity → entitydata
entity 作为参数,调用 entitydata 的 newInstance 方法。如下:
@ToStringAppendedProperty
public class ObservationRecordData extends AbstractRestBusinessData {
static public ObservationRecordData newInstance(final RandomSeedSupplier randomSeedSupplier, final ObservationRecord observationRecord) {
return new ObservationRecordData(randomSeedSupplier, observationRecord.getEntityId(),
observationRecord.getLessonDailyScheduleTimeTable() == null ? observationRecord.getNoticeOfDate() : observationRecord.getLessonDailyScheduleTimeTable().getDate(),
observationRecord.getContents(), observationRecord.getEntryDate(), Optional.ofNullablegetFullName).orElse(null);
}
public ObservationRecordData() {
super();
}
public ObservationRecordData(final RandomSeedSupplier randomSeedSupplier, final EntityId entityId) {
super(randomSeedSupplier, entityId);
}
public ObservationRecordData(final RandomSeedSupplier randomSeedSupplier, final String uid) {
super(randomSeedSupplier, uid);
}
public ObservationRecordData(final RandomSeedSupplier randomSeedSupplier, final EntityId entityId, final LocalDate localDate, final String contents, final LocalDateTime entryDate,
final String entryTeacherName) {
super(randomSeedSupplier, entityId);
this.dateWeek = localDate != null ? localDate.format(YYYYMDE) : "";
this.contents = contents;
this.entryDateLabel = entryDate != null ? entryDate.format(YYYYMD) : "";
this.entryTeacherName = entryTeacherName;
}
}
entitydata → entity
final IntraSchoolGroup intraSchoolGroup = decodeResolve(IntraSchoolGroup.class, SchoolClassData::new, parameter.getClassUid());
final List<SchoolObservationTag> tagList = parameter.getTagList() == null ? Collections.emptyList()
: parameter.getTagList().stream().map(o -> decodeResolve(SchoolObservationTag.class, SchoolObservationTagData::new, o)).collect(Collectors.toList());
V3
使用convertToValue (不一定要@CoverterTaget 注解)

final Teacher teacher = resolveCorrespondingEntityFor(teacherData, Teacher.class);
final TeacherData teacherData = convertToValue(teacher, TeacherData.class);
final List<Teacher> teacherList = teacherDataList.stream().map(o -> resolveCorrespondingEntityFor(o, Teacher.class)).collect(Collectors.toList());
final List<TeacherData> teacherDataList = convertToValueList(teacherList, TeacherData.class);
final List<TeacherData> teacherDataList = convertToValueList(teacherList, getConverterFactory().getConverterFor(TeacherData.class, Teacher.class));
final List<TeacherData> teacherDataList = teacherList.stream().map(o -> convertToValue(o, TeacherData.class)).collect(Collectors.toList());
使用 getConverterFactory().getConverterFor 获取转换方法(没有 ConverterTarget 注解)

public List<SchoolAbsentReasonData> findBySchoolIdAndYear(final ServiceRequestContext seriveReContext) {
final SchoolAbsentReasonLifecycle lifecycle = (SchoolAbsentReasonLifecycle) getLifecycleFactory().getLifecycleFor(SchoolAbsentReason.class);
final List<SchoolAbsentReason> schoolReasons = lifecycle.findBySchoolAndYear(seriveReContext.getCorrespondingSchool().getSchoolId(), seriveReContext.getCorrespondingSchoolYear().getYear()
.getYear());
final Converter<SchoolAbsentReasonData, SchoolAbsentReason> converter = getConverterFactory().getConverterFor (SchoolAbsentReasonData.class, SchoolAbsentReason.class);
return convertToValueList(schoolReasons, converter);
}

private SchoolYearData findschoolYearData(final ServiceRequestContext seriveReContext, final int year) {
final SchoolYearLifecycle lifecycle = (SchoolYearLifecycle) getLifecycleFactory().getLifecycleFor(SchoolYear.class);
final SchoolYear entity = lifecycle.findBySchoolIdAndYear(seriveReContext.getCorrespondingSchool().getSchoolId(), year);
final Converter<SchoolYearData, SchoolYear> converter = getConverterFactory().getConverterFor (SchoolYearData.class, SchoolYear.class);
final SchoolYearData data = converter.createDataFrom(getConversionContext(), entity);
return data;
}
使用 entityData 的 newInstance 进行实例化
VacationApplicationData.newInstance
@ConverterMapping 注解作用?
- skipMapping
- referentTransient
- publicTargetOnly
newInstance 和 convertToValue 的区别?
答: 若 entityData 类加了注解@ConverterTarget(targetEntity = Teacher.class),可以使用 convertToValue

-
若是 entityData 中定义的属性 比 entity 少,entity 转化成 entityData 后,entityData 能使用未定义的属性吗?
答: 不能,entityData 只能使用自己定义的属性。
-
何时使用 newInstance?何时使用 convertToValue?
@ManyToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH }, fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "RATING_ENTITYID", nullable = false)
private PhysicalTestRating rating;