Preventing duplicate ForeignKey generation
by Milo van der Zee
Hello all,
During development of applications I'm used to set the schema creation
to 'update' (hbm2ddl.auto = update). This makes life a bit easier.
Issue with the newer version of Hibernate is that the name of the
generated keys changed and so all keys are regenerated. For the large
databases I use this takes hours and has to be done every time a fresh
copy from production is taken to the development environment.
I do use meaningful names for the indexes where possible. But when using
abstract classes used by the entities that is not possible because the
same fields from the abstract are used by many entity classes and so
would end up having the same index names.
I checked the code that decides if the index needs to be created and
found that it only checks the name of the index. Not what the index
actually does. This is why I changed that piece of code to be a bit
smarter. It is desinged for simple constraints from one column to
another column. Not for multi to multi column indexes and constraints.
I created a Jira issue for it but nobody notices it and there are no
comments or anything else. So now I try it here :)
Jira HHH-10934 (https://hibernate.atlassian.net/browse/HHH-10934)
Code fragment I put in SchemaMigratorImpl.java:
private ForeignKeyInformation findMatchingForeignKey(ForeignKey foreignKey, TableInformation tableInformation) {
if (foreignKey.getName() ==null) {
return null;
}
/*
* Find existing keys based on referencing column and referencedTable
*/
String referencingColumn = foreignKey.getColumn(0).getName();
String referencedTableName = foreignKey.getReferencedTable().getName();
Iterable<ForeignKeyInformation> existingForeignKeys = tableInformation.getForeignKeys();
for (ForeignKeyInformation existingKey : existingForeignKeys) {
Iterable<ColumnReferenceMapping> columnReferenceMappings = existingKey.getColumnReferenceMappings();
for (ColumnReferenceMapping mapping : columnReferenceMappings) {
String existingReferencingColumn = mapping.getReferencingColumnMetadata().getColumnIdentifier().getText();
String existingReferencedTableName = mapping.getReferencedColumnMetadata().getContainingTableInformation().getName().getTableName().getCanonicalName();
if (referencingColumn.equals(existingReferencingColumn) && referencedTableName.equals(existingReferencedTableName)) {
return existingKey;
}
}
}
// If not yet found check based on key name return tableInformation.getForeignKey(Identifier.toIdentifier(foreignKey.getName()));
}
Or if you prever the Java 8 way:
private ForeignKeyInformation findMatchingForeignKey(ForeignKey foreignKey, TableInformation tableInformation) {
log.debug("findMatchingForeignKey");
if (foreignKey.getName() ==null)return null;
/*
* Find existing keys based on referencing column and referencedTable
*/
String referencingColumn = foreignKey.getColumn(0).getName();
String referencedTableName = foreignKey.getReferencedTable().getName();
Predicate<ColumnReferenceMapping> mappingPredicate = m -> referencingColumn.equals(m.getReferencingColumnMetadata().getColumnIdentifier().getText())
&& referencedTableName.equals(m.getReferencedColumnMetadata().getContainingTableInformation().getName().getTableName().getCanonicalName());
for (ForeignKeyInformation existingKey : tableInformation.getForeignKeys()) {
boolean found = StreamSupport.stream(existingKey.getColumnReferenceMappings().spliterator(),false).anyMatch(mappingPredicate);
if (found)return existingKey;
}
// If not yet found check based on key name return tableInformation.getForeignKey(Identifier.toIdentifier(foreignKey.getName()));
}
The calling method does not use the returned value. It only checks if
the returned value is null or not. So this could also be cleaned by
changing the method to return a boolean and then remove the for loop in
java-8 and use flatmap. But first let us agree on the validity of the
idea to change this piece of code.
I hope anybody would like to have a look at it and if there is any
change that the idea (not this actual very quick/dirty implementation)
goes into the system I'll clean it up and do some actual tests for more
complex database structures. I did not even check the junit tests yet.
At the moment it is good enough for me but I think it could be something
more people would benefit from.
Thanks,
Milo van der Zee
7 years, 6 months
Javassist dependency conflict in the ORM modules for WildFly
by Sanne Grinovero
Hi all,
there's a conflict in the Javassist versions of the WildFly modules of
Hibernate ORM 5.2.4.Final, but I'm not sure how to proceed as I'm not
familiar with this functionality.
The module declares *both*:
- a dependency to the WildFly provided Javassist: <module
name="org.javassist"/>
- inclusion of Hibernate's own version of Javassist: <resource-root
path="javassist-3.20.0-GA.jar"/>
Having both is causing trouble as they are both visible to the
Hibernate classloader; however I couldn't score a quick win with the
testsuiste by disabling either (all tests using these modules in the
Hibernate Search testsuite fail).
I suspect the problem is that JipiJapa also depends on the <module
name="org.javassist"/>, while ORM obviously needs the more recent
version of it.
I'm not familiar with what JipiJapa's business around Javassist; could
we keep the two clearly separated?
Especially if we want to make Byte Buddy a viable alternative, I
suspect the solution is that JipiJapa should not depend on Javassist
directly, but invoke a generic instrumentation SPI on Hibernate; also
with JipiJapa not able to see Javassist at all, we'd be in control of
the one and only Javassist version visible to ORM: the one we compile
and test with.
Thanks,
Sanne
7 years, 7 months
HHH-11144
by Gail Badner
HHH-11144 involves an entity that has 2 one-to-many associations with the
same type of entity, and both associations have orphanRemoval = true.
Andrea created a PR with test case at [1]
I am not sure if this is a valid mapping. I I would like your thoughts on
this.
Here is an excerpt of the relevant bits:
@Entity(name = "Item")
public static class Item {
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval
= true)
protected Set<ItemRelation> lowerItemRelations = new LinkedHashSet<>();
@OneToMany(mappedBy = "child", cascade = CascadeType.ALL, orphanRemoval =
true)
protected Set<ItemRelation> higherItemRelations = new LinkedHashSet<>();
}
@Entity(name = "ItemRelation")
public static class ItemRelation {
@ManyToOne(optional = false)
@JoinColumn(name = "PARENT_ID")
private Item parent;
@ManyToOne(optional = false)
@JoinColumn(name = "CHILD_ID")
private Item child;
}
HHH-11144 describes inconsistent behavior observed when
Item#lowerItemRelations and Item#higherItemRelations both contain the same
ItemRelation, then one of the collections is cleared.
If the non-cleared collection is uninitialized, then the ItemRelation is
orphan deleted.
If the non-cleared collection is initialized, then the orphan-deleted
ItemRelation is rescued when PERSIST_ON_FLUSH cascades to the non-cleared
collection elements. The next time the collections are loaded from the
database, both will still contain that same ItemRelation.
The spec says:
"Portable applications must otherwise not depend upon a specific order of
removal, and must not reassign an entity that has been orphaned to another
relationship or *otherwise attempt to persist it*"
Is Hibernate doing the right thing by rescuing an orphan-deleted entity?
In addition, this mapping allows a particular EntityRelation to be
associated with 2 different Item entities, which would mean that the same
ItemRelation would have 2 different owners with respect to orphan deletion..
The spec says:
"The orphanRemoval functionality is intended for entities that are privately
“owned” by their parent entity."
Does this mean that the mapping is invalid, since it would allow multiple
parent entities, or does it mean that the resulting behavior is undefined
(thus non-portable)?
Please let me know your thoughts.
Thanks,
Gail
[1] https://github.com/hibernate/hibernate-orm/pull/1607
7 years, 8 months
dynamic instantiation queries
by Steve Ebersole
Historically (well before JPA) HIbernate would handle dynamic instantiation
queries in cases where one of the arguments being an entity-reference by
passing just the entity's identifier rather than a complete reference to
the entity. To be clear, I am talking about a query like:
select new DTO( p ) from Person p
Hibernate implicitly treats this like:
select new DTO( p.id ) from Person p
and expects DTO to have a ctor taking the appropriate ID type.
JPA came along and also defines support for dynamic instantiation queries,
but does not specify one way or the other how this case should be handled.
I have been told other providers interpret this the opposite way. Makes
sense. I think it is time we at least allow that as an option. Or maybe a
nicer implementation that looks for both and picks the available one (if
that's not too much effort).
What do y'all think?
7 years, 9 months
Re: [hibernate-dev] Hibernate Commons project
by Guillaume Smet
On Mon, Jan 30, 2017 at 3:26 PM, Yoann Rodiere <yrodiere(a)redhat.com> wrote:
>
> On 30 January 2017 at 13:58, Guillaume Smet <guillaume.smet(a)gmail.com>
> wrote:
>
>> Note that the current version of hibernate-commons-annotations is
>> org.hibernate.common (without the s at the end, not org.hibernate as Yoann
>> stated it).
>>
> You're right. Wouldn't the simplest solution be to use the same groupId
> (without a "s") in our new repo?
>
I'm not so sure it's a good idea to share the groupId while it being a
completely different project.
I'm starting to think that maybe the good groupId for these common internal
projects could be org.hibernate.*internal*. We plan them to be purely
internal artifacts and we might as well state it.
What do you all think about it?
> Moving hibernate-commons-annotations is not such a good idea IMHO:
>> - it's licensed under the LGPL so it would force us to use this license
>> (or
>> relicense it or having different licenses for the submodules but they are
>> all bad ideas)
>>
>
> It sure seems complicated. But relicensing from LGPL to ASL2 may not be
> such a big deal, since LGPL seems stricter than ASL2.
> Couldn't we simply dual-license the whole repository under ASL2/LGPL? That
> way, previous users wouldn't need to be aware of the change, and new users
> could choose to comply with whichever suits them best.
>
Yeah, dual licensing might be the better solution. But I think it would be
OK with ASL2. Anyway, let's wait for Emmanuel to decide on this subject.
> - we would release a new version of this module each time we want to
>> upgrade the theme and I don't think it would be readable for consumers of
>> this preexisting artifact.
>>
>> The latter point is what worries me about centralizing all the utils in
>> the
>> same repo with the same lifecycle.
>>
>
> We already got through this discussion, but let's sum it up:
>
Not exactly. I was specifically talking about hibernate-commons-annotations
as it's a different beast: it's already released and people might use it in
their projects. Thus I don't think it's a good idea to think of it as a
purely internal project.
IMHO, it makes a difference.
--
Guillaume
7 years, 9 months
Query#iterate
by Steve Ebersole
I know I started a discussion of this somewhere with some of you, but I
cannot find it anymore.
I had suggested we consider getting rid of this Query#iterate method. I
just wanted to get everyone's opinions of this. Specifically, getting of
it in 6.0.
If anyone has dug much into the current Antlr 2 based parser you will be
familiar with this idea of shallow versus non-shallow queries. That is
where this comes into play. Query#iterate is a shallow query
(shallow=true). All other queries are non-shallow.
There are quite a few internal reasons to simply drop that method and get
rid of the idea of this shallow flag. I am happy to discuss these reasons
for those interested and that do not know.
But obviously we should not be getting rid of things just because of
"internal complications" if they are used by many users. I cannot speak to
whether any users use this, let alone how many.
Thoughts?
7 years, 9 months
[HSEARCH] heads up git users!
by Sanne Grinovero
Hi all,
I'm soon going to rename branches on the reference repository
[https://github.com/hibernate/hibernate-search]
"master" branch is going to be renamed "5.6"
"5.7" branch is going to be renamed "master"
If you keep this in mind, you should be able to avoid any trouble:
rebase as usual before sending PRs, just make sure you updated your
local references to match the reference and then use the new names
during the rebase.
If you get in trouble.. I'm open to help out.
Reminder: with git what matters is the commit signature: "renaming"
just means we're moving the labels from one branch to the other; the
branch itself is not being affected.
Thanks,
Sanne
7 years, 9 months
When is Dialect.requiresCastingOfParametersInSelectClause applied?
by Mark Rotteveel
After a hiatus of 6 months, I have gone back to my PR for
improving/replacing the Firebird dialect. I am running into a number of
test failures which I am working through to see if they are relevant or not.
One of the test failures I am looking at is
org.hibernate.jpa.test.criteria.basic.ConcatTest.testSelectCaseWithConcat
Firebird is rather picky about parameters occurring in the
select-clause, and they will almost always need to be cast to the
necessary type (and lengths). This tests seems to generate the following
query:
select
case
when concattest0_.id is not null then (?||?)
else 'Empty'
end as col_0_0_,
trim(both ' '
from
(?||?)) as col_1_0_
from
TEST_ENTITY concattest0_
I have implemented Dialect#requiresCastingOfParametersInSelectClause()
to return true, but unfortunately for this specific test it has no effect.
The absolute minimum SQL necessary for this to work (with some caveats) is:
select
case
when 1 = 1 then (?||?)
else 'Empty'
end as col_0_0_,
trim(both ' '
from
(cast(? as varchar(256))|| cast(? as varchar(256)))) as col_1_0_
from
TEST_ENTITY concattest0_
And preferably the (?||?) in the case should have an explicit cast for
each parameter as well, as otherwise each parameter is limited to 5
characters each (setting longer values will lead to a truncation exception).
Is this something that is fixable, and if so how? Or is this one of
those things where you just have to say 'aw, too bad, let it go' (or,
maybe: do it later if it is really necessary)?
With this specific failure out of the way: what is the general rule of
thumb of handling test failures in hibernate_core for a lesser-known
dialect?
I currently have 257 test failures (and 512 ignored) with Firebird and
my new dialect. I might add that some failures seem to be generic (eg
DriverManagerRegistrationTest, StandardRefCursorSupportTest,
NoCdiAvailableTest, XmlAccessTest, FetchProfileTest, IndexTest and some
others).
--
Mark Rotteveel
7 years, 9 months
Hibernate Search 5.6.0.Final and 5.7.0.CR1 released
by Yoann Rodiere
Hello,
We just released Hibernate Search 5.6.0.Final, the first stable release
featuring experimental support for Elasticsearch (2.x).
We also started the candidate release phase for Hibernate Search 5.7 by
releasing version 5.7.0.CR1, with support for ORM 5.2.7 and newer (but not
older, see the blog post).
This is the last step before 5.7 is released, so be sure to check it out so
you can share your thoughts with us before the release!
For more information, please see our blog:
http://in.relation.to/2017/01/30/hibernate-search-5-6-0-Final-and-5-7-0-CR1/
Cheers,
Yoann Rodière <yoann(a)hibernate.org>
Hibernate NoORM Team
7 years, 9 months