property() uses a fast path for the common case that the expression is a bean property path.
This will then fall back to using parse() when that isn't the case.
- append() adds to the sql with NO parsing
- parse() adds to the sql with parsing to replace logical bean paths into table alias placeholder + db column
In DatabaseConfig.isAutoLoadModuleInfo() it only used the querybean generated class registration is classes.isEmpty(). Changing this so that it only uses the loadModuleInfo flag.
This means, unless loadModuleInfo is set to false the classes that register with ebean will be a combination of both the explicitly registered ones plus the classes from the querybean generated EbeanEntityRegister.
In addition, this changes the classes from List to Set.
Stack trace observed:
java.lang.IndexOutOfBoundsException: The size must be at least 1
at io.ebeaninternal.server.deploy.id.IdBinderSimple.getIdInValueExpr(IdBinderSimple.java:135)
at io.ebeaninternal.server.deploy.BeanDescriptor.parentIdInExpr(BeanDescriptor.java:1634)
at io.ebeaninternal.server.deploy.BeanPropertyAssocManySqlHelp.addWhereParentIdIn(BeanPropertyAssocManySqlHelp.java:121)
at io.ebeaninternal.server.deploy.BeanPropertyAssocMany.addWhereParentIdIn(BeanPropertyAssocMany.java:342)
at io.ebeaninternal.api.LoadManyRequest.createQuery(LoadManyRequest.java:90)
at io.ebeaninternal.server.core.DefaultBeanLoader.loadMany(DefaultBeanLoader.java:39)
at io.ebeaninternal.server.core.DefaultServer.loadMany(DefaultServer.java:475)
at io.ebeaninternal.server.loadcontext.DLoadManyContext$LoadBuffer.loadMany(DLoadManyContext.java:215)
at io.ebean.common.AbstractBeanCollection.lazyLoadCollection(AbstractBeanCollection.java:90)
at io.ebean.common.BeanList.init(BeanList.java:141)
at io.ebean.common.BeanList.iterator(BeanList.java:327)
The history behind this is that originally there was a "profileId" concept where that was a int value that could be used as an "id" for a transactional method that we wanted to profile.
That went away and then the idea was that bytecode enhancement would determine the line number and we would use that but that was a bad idea and we ended up with lineNumber always as 0.
These days with StackWalker and DProfileLocation we can do this better that way so yeah. A followup to this is to add to the api a boolean flag as to whether a profile location should be with line numbers (which can change frequently due to refactoring etc)
As noted in comments in #2952
In the internals of SaveManyBeans we have:
- BUG: the deleteByParentId is hard delete and does not care for soft delete
- YUK: internally we have 3 ways of performing the orphan removal when we really want 2
This change fixes the BUG and fixes the YUK. It does this by removing the special case at: https://github.com/ebean-orm/ebean/blob/ebean-parent-13.11.3/ebean-core/src/main/java/io/ebeaninternal/server/persist/SaveManyBeans.java#L347-L350 ... and replacing it with the more common orphan removal code used when we do not have BeanCollection modifications.
The result of this change is that in SaveManyBeans internals we get back to have 2 ways to remove orphans.
- A BeanCollection with modifications: Orphans explicitly deleted using the known elements removed from the collection
- All other cases: Orphans as everything NOT in the collection that is going to be updated
orphanRemoval was not occurring when a loaded bean had a collection
replaced by a new BeanCollection (as opposed to a vanilla collection
like java.util.ArrayList).
Json marshalling a collection puts beans into BeanCollection and this
is part of the test that reproduced this issue.