【发布时间】:2013-12-18 16:42:24
【问题描述】:
我的数据库结构通过连接表将用户实体与角色耦合,用户类拥有关系并拥有一个引用角色实体集合的字段。
我想使用 SelectOneMenu 将用户链接到相关角色,但这当然会返回角色对象而不是集合。尽管 SelectManyMenu 会通过返回一个集合来绕过这个问题,但用户应该只分配一个角色。我正在使用 Omnifaces SelectItemsConverter 类来处理 ObjectString 转换,并认为我可以重写 getAsObject 以返回包含单个选定角色的集合。但是,这不起作用 - 调试表单处理显示在 JSF 验证过程中调用了 3 次 getAsObject 方法(其中三个关联的 SQL 调用查询 Roles 表)。第一次,选择的字符串值被传递,但接下来的两次调用包含一个空字符串,但尽管如此,角色设置器仅被调用一次(在更新模型阶段)并接收到正确的值。
我已经通过将角色实体添加到集合中的代码处理用户实体的持久性到数据库中来解决这个问题,但这似乎不是很优雅。如果可能的话,我宁愿将转换为用户实体所需的对象都放在一个地方。更重要的是,我不明白为什么我会看到这种行为,无论是正常的还是错误代码的结果,以及多个数据库查询在生产场景中可能产生的影响。不知道困扰着我(不是双关语!),因为这表明我无法理解 JSF 生命周期和 servlet 处理的来龙去脉。
包含 Role 实体的 SelectOneMenu 由此方法填充:
public static SelectItem[] getSelectItems(List<?> entities, boolean selectOne) {
int size = selectOne ? entities.size() + 1 : entities.size();
SelectItem[] items = new SelectItem[size];
int i = 0;
if (selectOne) {
items[0] = new SelectItem("", "Please select one item");
i++;
}
for (Object x : entities) {
items[i++] = new SelectItem(x, x.toString());
}
return items;
}
RolesSelectItemConverter.getAsObjec() 方法与标准 Omnifaces 实现相同,只是调用 Logger 以在调用该方法时进行标记。
调试跟踪:
INFO: START PHASE PROCESS_VALIDATIONS 3
INFO: RoleSelectItemsConverter.getAsObject called for UOComponent {javax.faces.component.html.HtmlSelectOneMenu@368dde0b} and value {exhibitor}
INFO: Attempting find all: com.rms.myconferenceprofile.entity.Role
INFO: [EL Fine]: sql: 2013-12-02 19:59:50.036--ServerSession(1830578621)--Connection(2011154278)--Thread(Thread[http-listener-1(1),5,main])--SELECT ID, DESCRIPTION, ROLE_NAME FROM ROLES
INFO: Attempting find all: com.rms.myconferenceprofile.entity.Role
INFO: [EL Fine]: sql: 2013-12-02 19:59:50.039--ServerSession(1830578621)--Connection(1600432374)--Thread(Thread[http-listener-1(1),5,main])--SELECT ID, DESCRIPTION, ROLE_NAME FROM ROLES
INFO: RoleSelectItemsConverter.getAsObject called for UOComponent {javax.faces.component.html.HtmlSelectOneMenu@368dde0b} and value {}
INFO: Attempting find all: com.rms.myconferenceprofile.entity.Role
INFO: [EL Fine]: sql: 2013-12-02 19:59:50.042--ServerSession(1830578621)--Connection(947366464)--Thread(Thread[http-listener-1(1),5,main])--SELECT ID, DESCRIPTION, ROLE_NAME FROM ROLES
INFO: [EL Fine]: sql: 2013-12-02 19:59:50.044--ServerSession(1830578621)--Connection(966514315)--Thread(Thread[http-listener-1(1),5,main])--SELECT t1.ID, t1.EMAIL, t1.FORENAME, t1.INACTIVE, t1.PASSWORD, t1.PHONE_NUMBER, t1.REGISTERED_DATETIME, t1.SURNAME, t1.ADDRESS_ID FROM USER_ROLE_MAP t0, USERS t1 WHERE ((t0.ROLE_ID = ?) AND (t1.ID = t0.USER_ID))
bind => [2]
INFO: Attempting find all: com.rms.myconferenceprofile.entity.Role
INFO: [EL Fine]: sql: 2013-12-02 19:59:50.048--ServerSession(1830578621)--Connection(119432927)--Thread(Thread[http-listener-1(1),5,main])--SELECT ID, DESCRIPTION, ROLE_NAME FROM ROLES
INFO: RoleSelectItemsConverter.getAsObject called for UOComponent {javax.faces.component.html.HtmlSelectOneMenu@368dde0b} and value {}
INFO: Attempting find all: com.rms.myconferenceprofile.entity.Role
INFO: [EL Fine]: sql: 2013-12-02 19:59:50.051--ServerSession(1830578621)--Connection(1342595455)--Thread(Thread[http-listener-1(1),5,main])--SELECT ID, DESCRIPTION, ROLE_NAME FROM ROLES
INFO: END PHASE PROCESS_VALIDATIONS 3
INFO: START PHASE UPDATE_MODEL_VALUES 4
INFO: SelectedRole setter called. Value: exhibitor
INFO: END PHASE UPDATE_MODEL_VALUES 4
我刚刚获得了更多调试信息,查看了 Role.equals() 被调用的次数以及比较对象是什么。它使阅读变得有趣!我可以通过可用的角色实体理解第一组迭代(当用户选择的角色被识别时迭代停止),但通过整个角色表的第二组迭代让我感到困惑。如果正在查看一张大表(例如国家或州),我的代码似乎效率很低!
INFO: START PHASE PROCESS_VALIDATIONS 3
INFO: RoleSelectItemsConverter.getAsObject called for UOComponent {javax.faces.component.html.HtmlSelectOneMenu@18a45031} and value {eventOrg}
INFO: Attempting find all: com.rms.myconferenceprofile.entity.Role
INFO: [EL Fine]: sql: 2013-12-02 20:54:37.596--ServerSession(1165546789)--Connection(544502930)--Thread(Thread[http-listener-1(3),5,main])--SELECT ID, DESCRIPTION, ROLE_NAME FROM ROLES
INFO: Attempting find all: com.rms.myconferenceprofile.entity.Role
INFO: [EL Fine]: sql: 2013-12-02 20:54:37.599--ServerSession(1165546789)--Connection(1032878258)--Thread(Thread[http-listener-1(3),5,main])--SELECT ID, DESCRIPTION, ROLE_NAME FROM ROLES
INFO: RoleSelectItemsConverter.getAsObject called for UOComponent {javax.faces.component.html.HtmlSelectOneMenu@18a45031} and value {}
INFO: Attempting find all: com.rms.myconferenceprofile.entity.Role
INFO: [EL Fine]: sql: 2013-12-02 20:54:47.789--ServerSession(1165546789)--Connection(948440937)--Thread(Thread[http-listener-1(3),5,main])--SELECT ID, DESCRIPTION, ROLE_NAME FROM ROLES
INFO: equals() called - comparison object {}
INFO: equals() called - comparison object {delegate}
INFO: equals() called - comparison object {exhibitor}
INFO: Attempting find all: com.rms.myconferenceprofile.entity.Role
INFO: equals() called - comparison object {eventOrg}
INFO: [EL Fine]: sql: 2013-12-02 20:54:47.793--ServerSession(1165546789)--Connection(1537445637)--Thread(Thread[http-listener-1(3),5,main])--SELECT ID, DESCRIPTION, ROLE_NAME FROM ROLES
INFO: RoleSelectItemsConverter.getAsObject called for UOComponent {javax.faces.component.html.HtmlSelectOneMenu@18a45031} and value {}
INFO: Attempting find all: com.rms.myconferenceprofile.entity.Role
INFO: [EL Fine]: sql: 2013-12-02 20:55:08.661--ServerSession(1165546789)--Connection(697639746)--Thread(Thread[http-listener-1(3),5,main])--SELECT ID, DESCRIPTION, ROLE_NAME FROM ROLES
INFO: equals() called - comparison object {}
INFO: equals() called - comparison object {delegate}
INFO: equals() called - comparison object {exhibitor}
INFO: equals() called - comparison object {eventOrg}
INFO: equals() called - comparison object {venueOrg}
INFO: equals() called - comparison object {ADMIN}
INFO: END PHASE PROCESS_VALIDATIONS 3
Xtreme Biker 提供帮助后的其他信息:
我没有使用 JSF Managed Beans,因为我知道支持将在下一个版本后撤销。 getSelectItems 方法包含在未明确限定范围的实用程序类中 - 由于我使用的是 CDI,我猜唯一等同于 @ViewScope 的范围是 @ConversationScope?此方法是从 NetBeans 自动生成的代码中提取的,因此可能不是最佳的。
【问题讨论】:
-
没有人吗?连BalusC都没有?这些多个 SQL 调用让我担心,因为这似乎是一个巨大的潜在服务器负载,我认为这是可以避免的......
标签: jpa jsf-2 entity converter