Csa*_*aba 3 java hibernate jpa
我有两个实体.一个继承自另一个.
例:
@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
}
Run Code Online (Sandbox Code Playgroud)
当我在EntityManager上使用现有汽车的id调用find()时,如下所示:
VehicleEntity vehicleEntity = entityManager.find(VehicleEntity.class, carID);
Run Code Online (Sandbox Code Playgroud)
我找回了一个代理对象,但我需要访问CarEntity类的特殊方法,因为我想设置一些新的参数.
有人可以帮我,我该怎么做?
当然这只是一个示例问题.更具体地说:在我调用find之后我正在检查返回对象的实例,如果它是"CarEntity"我设置参数,如果不是我什么都不做.我在"CarEntity"旁边有更多的继承类,我和以前一样做了同样的程序.我知道我可以用特定对象类的"find"来解决这个问题,但是我必须多次调用"find",当我正在寻找任何"VehicleEntity"时,我总是对实际对象感兴趣所以最好的是全球解决方案.
请考虑以下语句序列:
VehicleEntity vehicleEntityProxy = entityManager.getReference(VehicleEntity.class, carID);
VehicleEntity vehicleEntityInitialized = entityManager.find(VehicleEntity.class, carID);
Run Code Online (Sandbox Code Playgroud)
这vehicleEntityProxy是一个代理,因为你想要它(通过获得getReference).
在第二个语句中,您需要一个初始化的实例,因此您将获得它find:
按主键查找.搜索指定类和主键的实体.如果实体实例包含在持久性上下文中,则从那里返回它.
因此,find将检查实例是否已经在持久化上下文中,它将确定它是因为已经在第一个语句中创建了代理,它将初始化代理(因为它委托给Session.get永远不会返回未初始化实例的Hibernate )并将返回代理.
如果代替第一个语句,你已经加载了一个VehicleEntity与carIDid 具有懒惰一对一关联的其他实体,则会发生类似的事情.然后创建代理来代替真实实体实例,并且find当找到相同id的实体时,将从该方法返回该代理(并且如果尚未初始化则该代理).
所有这些进一步意味着instanceof在使用Hibernate代理时不是你的朋友(撇开一般来说,当谈到好的OOP代码时,它不是你的朋友).
作为一种解决方法,您可以使对象脱毛:
if (entity instanceof HibernateProxy) {
entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
Run Code Online (Sandbox Code Playgroud)
但这很乏味且容易出错(并且不必要地暴露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);
}
Run Code Online (Sandbox Code Playgroud)
现在,而不是:
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
}
Run Code Online (Sandbox Code Playgroud)
你可以做:
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);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3208 次 |
| 最近记录: |