我有两个实体。一个继承自另一个。
示例:
@Entity
@Table(name = "vehicle")
@Inheritance(strategy = InheritanceType.JOINED)
public class VehicleEntity {
//id, etc., all reference fetch type is LAZY
}
@Entity
@Table(name = "car")
public class CarEntity extends VehicleEntity {
//special parameters, all reference fetch type is LAZY
}
当我在EntityManager上使用现有汽车的id调用find()时:
VehicleEntity vehicleEntity = entityManager.find(VehicleEntity.class, carID);
我找回了一个代理对象,但是我需要访问CarEntity类的特殊方法,因为我想设置一些新的参数。
有人可以帮助我,我该怎么做?
当然这只是一个示例问题。更具体地说:在我调用find之后我正在检查返回对象的实例,如果它是“CarEntity”我设置参数,如果不是我什么都不做。我在“CarEntity”旁边有更多的继承类,我和以前一样做了同样的程序。我知道我可以用特定对象类的“find”来解决这个问题,但是我必须多次调用“find”,当我正在寻找任何“VehicleEntity”时,我总是对实际对象感兴趣所以最好的将是全球解决方案。
答案 0 :(得分:7)
考虑以下语句序列:
VehicleEntity vehicleEntityProxy = entityManager.getReference(VehicleEntity.class, carID);
VehicleEntity vehicleEntityInitialized = entityManager.find(VehicleEntity.class, carID);
vehicleEntityProxy
是代理,因为您希望它(通过getReference
获得)。
在第二个语句中,您需要一个初始化的实例,因此您将使用find
获取它:
按主键查找。搜索指定类的实体和 首要的关键。 如果实体实例包含在持久性中 上下文,从那里返回。
因此,find
将检查实例是否已经在持久化上下文中,它将确定是,因为已经在第一个语句中创建了代理,它将初始化代理(因为它委托给永远不会返回未初始化实例的Hibernate Session.get
)并返回代理。
如果代替第一个语句,您已经加载了一个与VehicleEntity
carID
id具有懒惰一对一关联的其他实体,则会发生类似的事情。然后创建代理来代替真实实体实例,并且当找到相同id的实体时,将从find
方法返回该代理(并且如果尚未初始化则该代理)。
所有这些进一步暗示 instanceof
在使用Hibernate代理时不是你的朋友(撇开一般来说,当谈到好的OOP代码时,它不是你的朋友)。
作为一种解决方法,您可以对对象进行去除:
if (entity instanceof HibernateProxy) {
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
但这很乏味且容易出错(并且不必要地暴露Hibernate特定的API)。此外,您可能还需要为所有关联对象执行此操作,因为它们也可以是代理。
更好的方法是使用经过验证的OOP结构和模式,例如Visitor
模式:
class Vehicle {
...
public void accept(VehicleVisitor visitor) {
}
}
class Car extends Vehicle {
...
public void accept(VehicleVisitor visitor) {
visitor.visit(this);
}
}
class Bus extends Vehicle {
...
public void accept(VehicleVisitor visitor) {
visitor.visit(this);
}
}
interface VehicleVisitor {
void visit(Car car);
void visit(Bus bus);
}
现在,而不是:
Vehicle vehicle = entityManager.find(Vehicle.class, vehicleId);
if (vehicle istanceof Car) {
Car car = (Car) vehicle;
// Do something with car
}
if (vehicle istanceof Bus) {
Bus bus = (Bus) vehicle;
// Do something with bus
}
你可以这样做:
class SomeVehicleVisitor implements VehicleVisitor {
public void visit(Car car) {
// Do something with car
}
public void visit(Bus bus) {
// Do something with bus
}
}
SomeVehicleVisitor visitor = ...
Vehicle vehicle = entityManager.find(Vehicle.class, vehicleId);
vehicle.accept(visitor);
答案 1 :(得分:2)
我理解的是,因为您正在获取代理对象,该对象应该是VehicleEntity类型,并且该代理对象中的目标对象应该是CarEntity。
所以,在我看来,你可能会使代理对象变得黯然失色,所以你可以获得CarEntity的真实对象。
然后,你可以打电话给CarEntity的特别成员。
我找到了链接,它会以通用方式对代理对象进行deproxy(因为你有很多继承的类)
Converting Hibernate proxy to real object
希望有所帮助......