HHH000506: Detaching an uninitialized collection with enabled filters from a session

I’m running Spring boot with spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true. Yes. I know. But this is not a high load application, and I like that it makes my development easy. Transactions are for writing. :blush:

Now that we parked that discussion, as a possible result of that setting, I am getting a lot of these errors: HHH000506: Detaching an uninitialized collection with enabled filters from a session: [nl.softworks.consilio.domain.Provider.groups#18], which is defined as:

	@ManyToMany
	@JoinTable(name = "provider_group",
			joinColumns = @JoinColumn(name = "provider_id"),
			inverseJoinColumns = @JoinColumn(name = "group_id"))
	private Set<Group> groups;

	@TenantId
	private String tenant;

Also, as you can see, it is a multitenant application. I’ve already asked this question on stackoverflow, and the answer is without doubt, but not clear. So I still do not quite understand what the problem is.

I figured to ask it here, maybe someone can explain to me what the problem exactly is, and if it is possible to solve it. Because both lazy load and tenant are official Hibernate features.

Ah, I see, the handling of (filtering on) tenant is stored in Hibernate’s Session object. Once the transaction ends, the session object is discarded, and thus the filtering can no longer be applied to any collection that is lazy loaded.

In my setup all the references use a technical key. The tenant id is only relevant when querying for an initial entry point into the data (e.g. finding all providers). Once these are loaded, any groups are referenced via their id, and tenant is not relevant anymore. So this only applies to datamodels that do not use techical keys.

Okay, now that I understand the problem, and read about the inverted fix, I’d like to voice my opinion. Not that it will matter (which I also understand), but alas.

So there are two ways to look at transactions.

  1. Transactions are for writing. Any explanation of transactions only talks about changing stuff, bank accounts usually, and this is the way how -for example- MySQL or Informix handles it. You read stuff, then do a begin work (just the semantics of these words already says a lot), execute inserts, updates, deletes, and then either commit or rollback. But outside the begin-commit you can just access the database. JPA/JTA transactions are no different, just in another context, but they’re still transactions. Hence after closing a transaction, and closing the write-session, it should be replaced with a readonly-session (with the tenant filter information present).
  2. Transactions are for reading and writing, then you get to version based locking, like Oracle has. In that scenario a close of a transaction automatically starts a new one, and there is never a moment where the tenant filter information is not present.

Since 2 is not the pattern of JPA/JTA transactions, I think 1 is the correct implementation, but IMHO not the pattern Hibernate uses now. (EBean, for example, implements number 1. Great persistency framework, if only it were used more, so issues are found more easily.)

Are you just concerned about the warning message or do you actually have a problem? The warning message might be inappropriate if only auto-enabled filters are active, but at the same time, this message only comes up when using the dangerous hibernate.enable_lazy_load_no_trans setting, so you can disable or ignore it if you understand what you’re doing.

Judging from what I’ve read, I don’t think I have a problem, but I can’t say this warning makes me feeling all warm and secure about that. I’m considering ditching the TenantId annotation, and doing it manually. The info is already in the datamodel, it’s just another way of implementing the separation.

And if ‘all access to transactional data should be done in a transaction’ then do give a few database vendors a call. :wink: Modifying data should be done in a transaction.

Judging from what I’ve read, I don’t think I have a problem, but I can’t say this warning makes me feeling all warm and secure about that.

And rightfully so IMO. You shouldn’t feel comfortable using a feature/setting that is called out to be dangerous in the documentation.

I’m considering ditching the TenantId annotation, and doing it manually. The info is already in the datamodel, it’s just another way of implementing the separation.

Not sure how that would “help”, except possibly getting rid of the warning at the cost of having the potential for a security hole unless you ensure every query that goes to the database has a proper filter applied manually.

And if ‘all access to transactional data should be done in a transaction’ then do give a few database vendors a call. :wink: Modifying data should be done in a transaction.

I hope you realize that a transaction can also make sense if you only read data. The snapshot transaction isolation level is the best example. Instead of reading data from inflight completing transactions, you might want to have a consistent view of your data across multiple query statements, which is when this comes in handy. If all you do is a single query statement per API call, then you likely won’t have a need for this, but lazy loading implies more than a single query, so depending on your requirements, you might want to rethink this oversimplification of “read does not require transactions”.

Formally you are totally right. I understand that with high load applications, rules are more strict. But with what I’m writing now, one or two users doing some administrative work, the chance of problems with inflight completing transactions is zero, while the hassle of eager loading data is plentiful. The reason why the option was conceived still is exists; and it’s a trade off I more than willing to take. I would sooner switch to schema-per-tenant than eager loading.

Do you know how to disable that warning under Spring?

I don’t know anything about Spring logging, so you should better ask that question in a Spring forum.

If you want to avoid lazy loading problems you have roughly 2 possibly options though:

  • Keep the session open longer until lazy loading is done (this is about the “open session-in-view” Spring setting I mentioned)
  • Fetch data into DTOs to get rid of lazy loading after a session ends

If you’re curious about the DTO approach, I can recommend you to look into Blaze-Persistence Entity-Views, which I developed to tackle such lazy loading problems.

Not logging the warning I can do. Check.

I understand the need for the DTOs, but as said, there also is another category of applications. The “MSAccess replacements” and they need to be quick and simple to develop. So I combine Spring, Vaadin, HSQLDB, and usually EBean (but this time I wanted to try Hibernate), all deployed in a single bootable jar. No RDBMS upgrade, no complex systemctl services, just one thing to start. Backup is just an rsync of the user’s directory. The goal is fast development for a very small group of concurrent users. You can make a lot of people happy, solving small but real problems, which such a stack. https://www.tbee.org/2024/03/30/simple-problems-simple-solutions-great-joy/ At work I’ll apply enterpricy patterns :laughing:

I’ve tried the spring.jpa.open-in-view=true setting, and disabled the lazy loading, but that did not work. I’ll take another look. I also did not see that warning that is mentioned. https://www.baeldung.com/spring-open-session-in-view

If this is just a “small”/toy application, then “open session-in-view” might be good enough, but the discussion it going into the territory of Spring, though this is a Hibernate ORM forum. I think I gave you enough information for you to find a good solution or ask follow up questions in Spring forums.
You’re welcome to ask questions here about Hibernate ORM if you have any.

Yes, thank you. You clarified the underlying problem.