使用标准JPA注释时,可以FetchType.LAZY
在非集合字段(即@ManyToOne
和@OneToOne
)上指定。在这种情况下,Hibernate似乎在内部使用“代理”获取。但是代理获取在继承方面存在问题,我认为最好将无代理获取与字节码检测结合使用。不幸的是,Hibernate仍然要求您在hbm
-file中指定“
no-proxy” 或使用特定于Hibernate的@LazyToOne
注释。
我的问题是:Hibernate是否支持配置选项,以便对所有非收集字段使用无代理获取策略FetchType.LAZY
?
这是我需要的:一方面,在大多数情况下,我只想使用JPA批注。另一方面,我想避免继承和惰性字段的问题。而且我不喜欢将所有内容包装在接口中的想法,因为我在当前项目中使用了DDD,所以我认为域模型中不应该存在任何样板垃圾,而只能是纯业务逻辑。
我有一个较差的解决方法的想法:通过使用字节码修改,我在@LazyToOne
所有@ManyToOne
出现的地方添加注释。但是我更喜欢内置的Hibernate功能(如果存在)。
这是代理获取的(众所周知的)问题,这使事情更清楚了:
@Entity @DiscriminatorColumn("t") @DiscriminatorValue("")
public abstract class A {
@Id private Integer id;
}
@Entity @DiscriminatorValue("B")
public abstract class B extends A {
}
@Entity @DiscriminatorValue("C")
public abstract class C extends A {
}
@Entity public class D {
@Id private Integer id;
@ManyToOne(fetch = FetchType.LAZY) private A a;
public A getA() {
return a;
}
}
准备:
D d = new D();
C c = new C();
d.setA(c);
em.persist(d);
并断言失败(在另一个EM中,在另一个事务中):
D d = em.createQuery("select d from D d", D.class).getSingleResult();
List<C> cs = em.createQuery("select c from C c", C.class).getResultList();
assert d.getA() instanceof C;
assert d.getA() == cs.get(0);
这是我要解决的上述问题的方法:
@Entity public class D {
@Id private Integer id;
@ManyToOne(fetch = FetchType.LAZY) @LazyToOne(LazyToOneOption.NO_PROXY)
private A a;
public A getA() {
return a;
}
}
而且我不希望在没有@LazyToOne
注释的情况下默认启用同一功能。
好吧,我放弃了接受答案。我仔细检查了Hibernate源代码,并得出结论:Hibernate本身不具备实现我所希望的属性。但是我想出了一个肮脏的技巧,这正是我想要的。因此,这里是:
public class DirtyHackedHibernatePersistence extends HibernatePersistence {
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public EntityManagerFactory createEntityManagerFactory(String persistenceUnitName,
Map properties) {
properties.put(AvailableSettings.PROVIDER, HibernatePersistence.class.getName());
Ejb3Configuration cfg = new Ejb3Configuration().configure(persistenceUnitName, properties);
if (cfg == null) {
return null;
}
cfg.buildMappings();
hackConfiguration(cfg);
return cfg.buildEntityManagerFactory();
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info,
Map properties) {
properties.put(AvailableSettings.PROVIDER, HibernatePersistence.class.getName());
Ejb3Configuration cfg = new Ejb3Configuration().configure(info, properties);
if (cfg == null) {
return null;
}
cfg.buildMappings();
hackConfiguration(cfg);
return cfg.buildEntityManagerFactory();
}
private void hackConfiguration(Ejb3Configuration cfg) {
System.out.println("Hacking configuration");
String noProxyByDefault = cfg.getProperties().getProperty("hibernate.hack.no-proxy-by-default", "false");
if (Boolean.parseBoolean(noProxyByDefault)) {
Iterator<?> iter = cfg.getClassMappings();
while (iter.hasNext()) {
hackClass((PersistentClass)iter.next());
}
}
}
private void hackClass(PersistentClass classMapping) {
Iterator<?> iter = classMapping.getPropertyIterator();
while (iter.hasNext()) {
Property property = (Property)iter.next();
if (property.getValue() instanceof ToOne) {
ToOne toOne = (ToOne)property.getValue();
if (toOne.isLazy()) {
toOne.setUnwrapProxy(true);
}
}
}
}
}
还必须有一个名为资源的资源,META- INF/services/javax.persistence.spi.PersistenceProvider
其中包含带有类名称的一行。
要使用此技巧,您应在中指定以下内容persistence.xml
:
<provider>packagename.DirtyHackedHibernatePersistence</provider>
<properties>
<property name="hibernate.hack.no-proxy-by-default" value="true"/>
</properties>
完整的示例可在此处获得。
请注意,如果删除该hibernate.hack.no-proxy-by-default
属性并重建项目,则两个断言都会被破坏。
我还将向Hibernate团队发布功能请求。
我尝试实现简单的一对多关联。在使用调试模式检查item对象后,我发现已经加载了list bids。但是List bids属性是用FetchType.Lazy注释的。一些书籍和网页声称FetchType.lazy是JPA提供者接受或拒绝的提示。但我想知道JPA提供程序在什么情况下忽略FetchType.lazy。提前谢谢你。
我在寻找一个选项来设置我的宇宙数据库收集TTL打开,但没有默认值。 这里我想在文档级别控制到期时间。我发现如果我在集合级别设置默认时间,它将覆盖文档级别中提到的时间。如果我错了,请纠正我。 基本上,我可以在数据资源管理器中设置它,但不确定如何通过C#代码进行设置。 由此https://docs.microsoft.com/en-us/azure/cosmos-db/time-to-live, 我看
我试图观察下面的JPA2/Hibernate4代理行为, //延迟加载的循环实体: //持久实体: //输出: //加载外部实体: //输出: 令我惊讶的是,上面加载的外部实体仍然是普通实体,但我希望它是,这是由于造成的。我可能错过了一些东西,那怎么做才对呢?一个简单而具体的例子是非常感谢! @编辑 根据的回答,我修改了代码,并在下面的SE模式下对其进行了调试,既不能生成,也不能代理
JPA实体与具有关系: 和与有多个关系: 在创建新实例并持久化它之后,仍然是。但当我使用空的: DAO由Spring Data JPA实现。 Spring Boot 2.0.4.Release Spring Data JPA 2.0.4.Release Hibernate 5.2.17.Final Hibernate JPA 2.1 1.0.2.Final
所以我有一个三层应用程序。通过spring boot starter jpa自动配置hibernate。以及使用@EnableJpaRepositories(enttityManagerFactory、transactionManager、basepackages)的配置类 我的问题是,如果控制器调用从数据库获取实体的服务,那么该服务是否可以将该实体传递给其他组件,而不会分离,考虑到它仍然是同一个
无法在jetty中启动spring-引导,即使使用以下配置,什么配置不正确