Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple object instances due to foreign reference cycles? #278

Open
ewills opened this issue Nov 15, 2022 · 1 comment
Open

Multiple object instances due to foreign reference cycles? #278

ewills opened this issue Nov 15, 2022 · 1 comment

Comments

@ewills
Copy link

ewills commented Nov 15, 2022

I've got a scenario where a DatabaseTable A has an eager ForeignCollectionField referring to table B, which has a foreign DatabaseField referring to table C, which has a foreign field referring back to table A. When querying for an uncached instance of A, I'm seeing:

  1. Check the cache (weak ReferenceObjectCache) for a cached instance when mapping rows and return it https://github.com/j256/ormlite-core/blob/master/src/main/java/com/j256/ormlite/stmt/mapped/BaseMappedQuery.java#L49 otherwise:
  2. Create a new instance https://github.com/j256/ormlite-core/blob/master/src/main/java/com/j256/ormlite/stmt/mapped/BaseMappedQuery.java#L54
  3. Iterate resultsFieldTypes https://github.com/j256/ormlite-core/blob/master/src/main/java/com/j256/ormlite/stmt/mapped/BaseMappedQuery.java#L58
  4. Recursively assign fields, eventually calling createForeignObject to create a new instance of A while iterating the fields on an instance of C https://github.com/j256/ormlite-core/blob/master/src/main/java/com/j256/ormlite/field/FieldType.java#L574
  5. The instance of A from step 4 is hydrated and added to the object cache https://github.com/j256/ormlite-core/blob/master/src/main/java/com/j256/ormlite/field/FieldType.java#L1077
  6. The instance of A from step 2 is added to the object cache https://github.com/j256/ormlite-core/blob/master/src/main/java/com/j256/ormlite/stmt/mapped/BaseMappedQuery.java#L94

At this point I've got the instance of A from step 2 (and 6) in my object cache along with an instance of C that has a foreign DatabaseField referring to the instance of A from step 4.

I could avoid this particular scenario by lowering maxForeignAutoRefreshLevel on either B's reference to C or C's reference to A, but we add columns to our data model often and I'd rather not consider these possible cycles each time we do this!

So my question is: would it make sense to modify BaseMappedQuery mapRow() to add newly-created instances to the object cache prior to resolving foreign references (i.e., between steps 2 and 3 above)? That way (I think) the subsequent mapRow calls for the foreign references would be find the cached instance from step 2 rather than creating a new instance?

I can also imagine that it might be a bad idea to add partially-hydrated instances to the object cache, so this idea may be a nonstarter!

@j256
Copy link
Owner

j256 commented Nov 24, 2022

Sorry to not respond sooner @ewills. Interesting. You are pushing the limits of my experience in this area. It might be interesting to have 2 caches. One specifically for the call frame that is tracking the objects that are are partially hydrated so they don't get doubly created. Then the other to hold the hydrated objects. I agree that putting the partially hydrated instances in the cache might be bad unless there was some sort of lock in place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants