更新:我考虑了克里斯的答案,但没有帮助 - 我仍然面临着这个问题。我已经更新了下面的代码以包含Chris的答案。需要注意的是,在实施Chris的建议时,关系是持久的,但没有反映在view.xhtml页面上。我不得不用调用GenericDao.update()
返回的对象替换db对象。
我有以下关系:
许多PurchaseOrders(PO)的一位客户 许多发票的一个PO。
我已经阅读了双向关系,我知道如果我有双向关系,我应该在更新实体时更新关系的两面。
我执行以下步骤:
我观察到所有实体和关系都是持久的,但不会显示客户订单列表。
查看客户:
查看PurchaseOrder:
数据库查询:
> select * from customer; > +----+------------+ > | ID | NAME | > +----+------------+ > | 1 | Customer 1 | > +----+------------+ > 1 row in set (0.00 sec) > > mysql> select * from purchaseorder; > +----+---------+-------------+ > | ID | NAME | customer_id | > +----+---------+-------------+ > | 1 | Order 1 | 1 | > +----+---------+-------------+ > 1 row in set (0.00 sec) > > mysql> select * from invoice; > +----+-----------+------------------+ > | ID | NAME | purchaseorder_id | > +----+-----------+------------------+ > | 1 | Invoice 1 | 1 | > +----+-----------+------------------+ > 1 row in set (0.00 sec)
数据库反映了已配置实体之间的关系,因此我知道我的更改是持久的,据我所知,我已经实现了客户PO关系,与PO-Invoice关系的实现方式相同。由于PO的发票清单已正确更新,我认为我没有系统性问题,所以在客户PO和PO发票关系的实施之间必然存在不同之处,但我无法发现它。
为什么我没有看到我的客户的PO列表,即使为客户配置了明确的PO?
任何帮助将不胜感激。
类(为简洁而截断): 实体 客户
private int id; //@Id and @GeneratedValue(IDENTITY) on getter
private String name;
@OneToMany(mappedBy="customer")
private Set<PurchaseOrder> purchaseOrders;
public Customer()
{
purchaseOrders = new HashSet<PurchaseOrder> ();
}
public Set<PurchaseOrder> getPurchaseOrders()
{
return this.purchaseOrders;
}
public void setPurchaseOrders(Set<PurchaseOrder> orders)
{
this.purchaseOrders = orders;
}
public void addPurchaseOrder(PurchaseOrder purchaseOrder)
{
this.purchaseOrders.add(purchaseOrder);
//this IF is important for avoiding an infinite loop
if (purchaseOrder.getCustomer() != this)
{
purchaseOrder.setCustomer(this);
}
}
public void removePurchaseOrder(PurchaseOrder purchaseOrder)
{
this.purchaseOrders.remove(purchaseOrder);
//this IF is important to avoid an infinite loop
if(purchaseOrder.getCustomer() != null)
{
purchaseOrder.removeFromCustomer(this);
}
}
PO
private int id; //@Id and identity column
private String name;
@ManyToOne
@JoinColumn(name="customer_id")
private Customer customer;
@OneToMany(mappedBy="purchaseOrder")
private Set<Invoice> invoices;
public PurchaseOrder() {
invoices = new HashSet<Invoice> ();
}
public Customer getCustomer()
{
return this.customer;
}
public void setCustomer(Customer customer)
{
this.customer = customer;
}
public void addToCustomer(Customer customer)
{
//this IF is important for avoiding an infinite loop
if(!customer.getPurchaseOrders().contains(this))
{
customer.addPurchaseOrder(this);
}
this.customer = customer;
}
public void removeFromCustomer(Customer customer)
{
//this IF is important for avoiding an infinite loop
if(customer.getPurchaseOrders().contains(this))
{
customer.removePurchaseOrder(this);
}
this.customer = null;
}
public Set<Invoice> getInvoices()
{
return this.invoices;
}
public void setInvoices(Set<Invoice> invoices)
{
this.invoices = invoices;
}
public void addInvoice(Invoice invoice)
{
this.invoices.add(invoice);
//this IF is important for avoiding an infinite loop
if (invoice.getPurchaseOrder() != this)
{
invoice.addToPurchaseOrder(this);
}
}
public void removeInvoice(Invoice invoice)
{
this.invoices.remove(invoice);
//this IF is important to avoid an infinite loop
if(invoice.getPurchaseOrder() != null)
{
invoice.removeFromPurchaseOrder(this);
}
}
发票
private int id; //@Id and identity column
private String name;
@ManyToOne
@JoinColumn(name="purchaseorder_id")
private PurchaseOrder purchaseOrder;
public Invoice() {
}
public PurchaseOrder getPurchaseOrder()
{
return this.purchaseOrder;
}
public void setPurchaseOrder(PurchaseOrder purchaseOrder)
{
this.purchaseOrder = purchaseOrder;
}
public void addToPurchaseOrder(PurchaseOrder purchaseOrder)
{
//this IF is important for avoiding an infinite loop
if(!purchaseOrder.getInvoices().contains(this))
{
purchaseOrder.addInvoice(this);
}
this.purchaseOrder = purchaseOrder;
}
public void removeFromPurchaseOrder(PurchaseOrder purchaseOrder)
{
//this IF is important for avoiding an infinite loop
if(purchaseOrder.getInvoices().contains(this))
{
purchaseOrder.removeInvoice(this);
}
this.purchaseOrder = null;
}
GenericDao(所有其他DAO的父母)
@Stateful
public class GenericDao<T extends Serializable, PK> implements IGenericDao<T, PK>
{
@PersistenceContext(unitName = "my_PU")
protected EntityManager em;
private Class<T> type;
public Class<T> getType()
{
return type;
}
public void setType(Class<T> type)
{
this.type = type;
}
public void create(T newObject)
{
em.persist(newObject);
}
public T read(PK id)
{
return em.find(type, id);
}
public T update(T transientObject)
{
return em.merge(transientObject);
}
public void delete(T objectToDelete)
{
em.remove(objectToDelete);
}
public T getResultObject(String namedQuery, Map<String, Object> criteria)
throws DatabaseException
{
List<T> records = getResultSetList(namedQuery, criteria);
if(records.isEmpty())
{
return null;
}
else if (records.size() != 1)
{
throw new DatabaseException("Too many records found!");
}
else
{
return records.remove(0);
}
}
}
控制器 CustomerController
@RequestScoped
public class CustomerController extends FormRequestController
{
@Inject
private HTMLDataTableActionBean htmlDataTableActionBean;
@EJB
private ICustomerDao customerDao;
@Inject
private Customer customer;
@PostConstruct
public void init() throws DatabaseException
{
setEntityObjectList(findAll());
if (null == this.getCustomer())
{
setCustomer(new Customer());
}
}
public void processRequest(FormActionToPerform action) throws DatabaseException
{
switch (action)
{
case SHOW_ADD_VIEW:
setCustomer(new Customer());
break;
case SHOW_VIEW_FOR_LIST:
setEntityObjectList(findAll());
break;
case SHOW_EDIT_VIEW:
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
setCustomer((Customer) getHtmlDataTableActionBean()
.getSelectedEntityObject());
break;
case SHOW_DELETE_VIEW:
setCustomer((Customer) getHtmlDataTableActionBean()
.getSelectedEntityObject());
delete();
break;
}
}
public String doShowUIView(FormActionToPerform action)
{
String responseURL = "fail.xhtml";
if (null == this.customer)
{
return responseURL;
}
else
{
switch (action)
{
case SHOW_ADD_VIEW:
responseURL = "customer.xhtml";
break;
case SHOW_EDIT_VIEW:
responseURL = "customer.xhtml";
break;
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
responseURL = "viewCustomer.xhtml";
break;
case SHOW_DELETE_VIEW:
responseURL = "customerList.xhtml";
break;
case SHOW_VIEW_FOR_LIST:
if (this.entityObjectList.size() == 0)
{
setErrorMessage("No customers to display");
}
responseURL = "customerList.xhtml";
break;
default:
responseURL = "index.xhtml";
}
}
return responseURL;
}
public String save()
{
String url = "success.xhtml";
Customer existingCustomer = null;
try
{
existingCustomer =
customerDao.getCustomerByName(this.getCustomer().getName());
if(existingCustomer != null)
{
//there's already a customer with this name, don't make a new one
setErrorMessage("Customer already exists");
url = "fail.xhtml";
}
customerDao.update(customer);
}
catch (DatabaseException e)
{
setErrorMessage(e.toString());
e.printStackTrace();
url = "fail.xhtml";
}
return url;
}
}
POController
@RequestScoped
public class PurchaseOrderController extends FormRequestController
{
@Inject
private HTMLDataTableActionBean htmlDataTableActionBean;
@EJB
private IPurchaseOrderDao purchaseOrderDao;
@EJB
private IInvoiceDao invoiceDao;
@EJB
private ICustomerDao customerDao;
@Inject
private PurchaseOrder purchaseOrder;
private List<SelectItem> customerList;
private String selectedCustomer;
@PostConstruct
public void init() throws DatabaseException
{
setEntityObjectList(findAll());
if (null == purchaseOrder)
{
purchaseOrder = new PurchaseOrder();
setEditMode(false);
}
}
public void processRequest(FormActionToPerform action)
throws DatabaseException
{
switch (action)
{
case SHOW_ADD_VIEW:
setPurchaseOrder(new PurchaseOrder());
break;
case SHOW_VIEW_FOR_LIST:
setEntityObjectList(findAll());
break;
case SHOW_EDIT_VIEW:
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
{
setPurchaseOrder(
(PurchaseOrder)getHtmlDataTableActionBean().
getSelectedEntityObject());
}
break;
case SHOW_DELETE_VIEW:
{
setPurchaseOrder(
(PurchaseOrder)getHtmlDataTableActionBean().
getSelectedEntityObject());
delete();
}
break;
}
}
String doShowUIView(FormActionToPerform action)
{
String responseURL = "fail.xhtml";
switch (action)
{
case SHOW_ADD_VIEW:
responseURL = "purchaseOrder.xhtml";
break;
case SHOW_EDIT_VIEW:
setEditMode(true);
setComponent(null);
responseURL = "purchaseOrder.xhtml";
break;
case SHOW_DELETE_VIEW:
case SHOW_VIEW_FOR_LIST:
if (this.entityObjectList.size() == 0)
{
setErrorMessage("No orders to display");
}
responseURL = "purchaseOrderList.xhtml";
break;
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
responseURL = "viewPurchaseOrder.xhtml";
break;
default:
responseURL = HOME;
}
return responseURL;
}
public String save()
{
String responseURL = "fail.xhtml";
try
{
PurchaseOrder dbPurchaseOrder =
purchaseOrderDao.getPurchaseOrderByName(purchaseOrder.getName());
if(dbPurchaseOrder == null)
{
dbPurchaseOrder = purchaseOrder;
}
Customer customer = customerDao.getCustomerByName(selectedCustomer);
dbPurchaseOrder.addToCustomer(customer);
purchaseOrder = purchaseOrderDao.update(dbPurchaseOrder);
//replace the not-yet-persisted dbPurchaseOrder object in customer
//with the persisted purchaseOrderobject returned from the update()
//call above.
customer.removePurchaseOrder(dbPurchaseOrder);
customer.addPurchaseOrder(purchaseOrder);
customerDao.update(customer);
System.out.println("# of Purchase orders for customer: "+
purchaseOrder.getCustomer().getPurchaseOrders().size());
//Output: # of Purchase orders for customer: 1
responseURL = "success.xhtml";
}
catch (DatabaseException e)
{
e.printStackTrace();
setErrorMessage(e.toString());
responseURL = null;
}
return responseURL;
}
}
InvoicesController
@RequestScoped
public class InvoiceController extends FormRequestController
{
@Inject
private HTMLDataTableActionBean htmlDataTableActionBean;
@EJB
private IInvoiceDao invoiceDao;
@Inject
private Invoice invoice;
@EJB
private IPurchaseOrderDao purchaseOrderDao;
private List<SelectItem> purchaseOrderList;
private String selectedPurchaseOrder;
@PostConstruct
public void init() throws DatabaseException
{
setEntityObjectList(findAll());
if (null == invoice)
{
invoice = new Invoice();
setEditMode(false);
}
}
public void processRequest(FormActionToPerform action) throws DatabaseException
{
switch (action)
{
case SHOW_ADD_VIEW:
break;
case SHOW_VIEW_FOR_LIST:
setEntityObjectList(findAll());
break;
case SHOW_EDIT_VIEW:
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
{
setInvoice((Invoice)getHtmlDataTableActionBean().
getSelectedEntityObject());
}
break;
case SHOW_DELETE_VIEW:
{
setInvoice((Invoice)getHtmlDataTableActionBean().
getSelectedEntityObject());
delete();
}
break;
}
}
String doShowUIView(FormActionToPerform action)
{
String responseUrl = "fail.xhtml";
if (null == invoice)
{
System.out.println("invoice == null");
return responseUrl;
}
else
{
switch (action)
{
case SHOW_ADD_VIEW:
responseUrl = "invoice.xhtml";
break;
case SHOW_EDIT_VIEW:
setEditMode(true);
setComponent(null);
responseUrl = "invoice.xhtml";
break;
case SHOW_VIEW_TO_VIEW_SELECTED_OBJECT:
responseUrl = "viewInvoice.xhtml";
break;
case SHOW_DELETE_VIEW:
case SHOW_VIEW_FOR_LIST:
if (this.entityObjectList.size() == 0)
{
setErrorMessage("no invoices to display");
}
responseUrl = "invoiceList.xhtml";
break;
default:
responseUrl = "index.xhtml";
}
}
return responseUrl;
}
public String save()
{
String responseUrl = "fail.xhtml";
try
{
Invoice dbInvoice = invoiceDao.getInvoiceByName(invoice.getName());
if(dbInvoice == null)
{
//this is a new invoice
dbInvoice = invoice;
}
PurchaseOrder purchaseOrder =
purchaseOrderDao.getPurchaseOrderByName(selectedPurchaseOrder);
dbInvoice.addToPurchaseOrder(purchaseOrder);
invoice = invoiceDao.update(dbInvoice);
//replace the not-yet-persisted dbInvoice object in purchaseOrder
//with the persisted invoice object returned from the update() call above.
purchaseOrder.removeInvoice(dbInvoice);
purchaseOrder.addInvoice(invoice);
purchaseOrderDao.update(purchaseOrder);
System.out.println("# of Invoices for purchase order: "+
invoice.getPurchaseOrder().getInvoices().size());
//Output: # of Invoices for purchase order: 1
responseUrl = "success.xhtml";
}
catch (Exception e)
{
System.out.println(e.toString());
e.printStackTrace();
setErrorMessage(e.toString());
}
return responseUrl;
}
}
FormRequestController
public abstract class FormRequestController implements NavigationConstants
{
protected enum FormActionToPerform {
SHOW_ADD_VIEW,
SHOW_EDIT_VIEW,
SHOW_DELETE_VIEW,
SHOW_VIEW_TO_VIEW_SELECTED_OBJECT,
SHOW_VIEW_FOR_LIST;
}
protected FacesContext context;
protected List<?> entityObjectList;
private UIComponent component;
protected boolean editMode;
protected String componentId = null;
public String showViewDataTable() throws DatabaseException {
processRequest(FormActionToPerform.SHOW_VIEW_FOR_LIST);
return doShowUIView(FormActionToPerform.SHOW_VIEW_FOR_LIST);
}
public String showViewToAdd() throws DatabaseException {
processRequest(FormActionToPerform.SHOW_ADD_VIEW);
return doShowUIView(FormActionToPerform.SHOW_ADD_VIEW);
}
public String showViewToEdit() throws DatabaseException {
processRequest(FormActionToPerform.SHOW_EDIT_VIEW);
return doShowUIView(FormActionToPerform.SHOW_EDIT_VIEW);
}
public String showViewToDeleteDetails() throws DatabaseException {
processRequest(FormActionToPerform.SHOW_DELETE_VIEW);
return doShowUIView(FormActionToPerform.SHOW_DELETE_VIEW);
}
public String showViewToViewDetails() throws DatabaseException {
processRequest(FormActionToPerform.SHOW_VIEW_TO_VIEW_SELECTED_OBJECT);
return doShowUIView(FormActionToPerform.SHOW_VIEW_TO_VIEW_SELECTED_OBJECT);
}
abstract String doShowUIView(FormActionToPerform action);
abstract void processRequest(FormActionToPerform action) throws DatabaseException;
protected void bindData() {
}
abstract String save();
abstract void delete() throws DatabaseException;
public List<?> getEntityObjectList() {
return entityObjectList;
}
public void setEntityObjectList(List<?> entityObjectList) {
this.entityObjectList = entityObjectList;
}
public FacesContext getContext() {
setContext(FacesContext.getCurrentInstance());
return context;
}
public void setContext(FacesContext context) {
this.context = context;
}
public UIComponent getComponent() {
return component;
}
public void setComponent(UIComponent component) {
this.component = component;
}
}
我正在使用Customer#purchaseOrders
对PurchaseOrder#invoices
和h:dataTable
进行迭代。 SO一直误认为我的JSF代码是错误格式化的代码,并告诉我缩进它,所以我无法显示我的网页代码,但希望上面有足够的内容来发现我的错误。
提前感谢您的时间。
答案 0 :(得分:1)
如果JPA设置为使用属性访问权限,则set / get方法中不应包含逻辑。 set方法中的逻辑将导致JPA在构建实体时触发延迟集合等,并且可能具有其他不利影响,具体取决于提供者内部。我会切换你的注释,使它们在字段上,或删除
if(!purchaseOrder.getInvoices().contains(this))
{
purchaseOrder.addInvoice(this);
}
来自set方法的逻辑。应用程序仍然可以使用addInvoice并设置关系的两侧,因为JPA在加载实体时不使用addInvoice方法。