我正在 javafx 中开发一个应用程序,该应用程序通过 RMI 与 EAR 连接。该 EAR 连接到 SQLServer DB 并使用 hibernate 映射 POJOS。
这些 POJOS 包含双向 OneToMany 和 ManyToOne 关系。因此,这些关系被映射为 List 。
Company.java
@Entity
@Table(name = "Company")
public class Company implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@Column(name="id_company",nullable = false)
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@OneToMany(mappedBy = "company",cascade = CascadeType.ALL )
@ElementCollection
private List<Client> Clients;
//GETTERS&SETTERS
}
Client.java
@Entity
@Table(name = "Client")
public class Client implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@Column(name="id_client",nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne
private Company company;
//GETTERS&SETTERS
}
当我执行此操作时,T 是公司:
public default T selectById(Serializable id, Class<T> entityClass,Session session)throws HibernateException {
T obj = null;
obj = session.get(entityClass, id);
return obj;
}
结果是带有所有相应信息的 POJO,但在调试 View 中看到:
该对象已成功实例化,并且我的桌面应用程序完美地接收了该对象,但是如果该对象使用接收对象 Company 作为参数的方法再次将其发送到服务器,则会出现此错误。
javax.ejb.EJBException: java.io.StreamCorruptedException: serialVersionUID does not match!
at org.jboss.as.ejb3.remote.AssociationImpl.receiveInvocationRequest(AssociationImpl.java:128)
at org.jboss.ejb.protocol.remote.EJBServerChannel$ReceiverImpl.handleInvocationRequest(EJBServerChannel.java:450)
at org.jboss.ejb.protocol.remote.EJBServerChannel$ReceiverImpl.handleMessage(EJBServerChannel.java:188)
at org.jboss.remoting3.remote.RemoteConnectionChannel.lambda$handleMessageData$3(RemoteConnectionChannel.java:430)
at org.jboss.remoting3.EndpointImpl$TrackingExecutor.lambda$execute$0(EndpointImpl.java:926)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.io.StreamCorruptedException: serialVersionUID does not match!
at org.jboss.marshalling.AbstractClassResolver.resolveClass(AbstractClassResolver.java:108)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadClassDescriptor(RiverUnmarshaller.java:1025)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1354)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:275)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:223)
at org.jboss.marshalling.river.RiverUnmarshaller.readFields(RiverUnmarshaller.java:1856)
at org.jboss.marshalling.river.RiverUnmarshaller.doInitSerializable(RiverUnmarshaller.java:1769)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1397)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:275)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:208)
at org.jboss.marshalling.AbstractObjectInput.readObject(AbstractObjectInput.java:41)
at org.jboss.ejb.protocol.remote.EJBServerChannel$RemotingInvocationRequest.getRequestContent(EJBServerChannel.java:805)
at org.jboss.as.ejb3.remote.AssociationImpl.receiveInvocationRequest(AssociationImpl.java:126)
... 7 more
Caused by: an exception which occurred:
in field com.persistence.pojo.Company.Clients
in object com.persistence.pojo.Company@47368172
in object of type com.persistence.pojo.Company
我正在使用 Wildfly10.x 服务器。 hibernatecore的版本是5.2.17.Final
如果解释得不好,我很抱歉,但该项目非常复杂,本质上我需要 hibernate 来映射到 List 对象而不是 Persistedbag。
最佳答案
这里的问题是,您从 hibernate 获取的对象属于某个 hibernate 代理类,而不是您实际的实体类。这是 hibernate 状态的正常行为。 这个代理类是自动生成的,它的serialVersionUID也是自动生成的。
一般来说,直接序列化/发送实体类对象不是一个好习惯,因为这样的问题,而且还因为延迟初始化的问题以及所有与将对象绑定(bind)到实体管理器上下文相关的问题。
最常见的解决方案是创建“数据传输对象”或 DTO,它们可能具有相同的字段(或非常相似 - 例如用字符串替换枚举等,具体取决于您的需要),仅此而已。根据您的示例,您可以拥有这样的类(class):
public class CompanyDTO implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private List<ClientDTO> Clients;
//GETTERS&SETTERS
}
(以此类推,您也需要创建 ClientDTO 类)。
使用此类来进行外部(外部不一定是远程的,只要您需要与 EM 上下文分离的地方)通信。
您可以手动填充它,或通过任何其他方式(例如使用 BeanUtils 进行反射,带有复制属性的 Company 参数的构造函数 [我不建议这样做,因为它会中断应用程序层分离,但出于本次对话的目的这是一种有效的方法])。唯一重要的是您从实体管理器上下文中填充它
关于java - Hibernate OneToMany 关系是 PersistentBag 而不是 List,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50328616/