How to always generate `Table` constructors for JOOQ 3.11's implicit-join feature? - code-generation

JOOQ 3.11 introduced an awesome feature called implicit joins.
Unfortunately, the new feature causes trouble with our half-baked application modularization.
Symptom
Looking at the JOOQ generator source code, I found out that the following constructor for the generated class FileStorage (a Table subclass) are generated only if the JOOQ generator finds a foreign key referencing FILE_STORAGE:
public <O extends Record> FileStorage(Table<O> child, ForeignKey<O, FileStorageRecord> key) {
super(child, key, FILE_STORAGE);
}
This leads to compilation errors in our build that generates the JOOQ model for each application module separately:
We use one schema per application-module (e.g. billing) and one special schema shared that is visible from every application-module. The JOOQ metamodel for shared is generated in complete isolation from the rest, so during the code-generation for shared, a foreign key from INVOICE (module billing) to FILE_STORAGE (module shared) will not be visible to the JOOQ generator. Thus, the above constructor is missing on the FILE_STORAGE side but not on the INVOICE side of the JOOQ model and we end up with compilation errors in Invoice from billing's JOOQ model.
Question
Short of duplicating the JOOQ model for shared in 10+ application modules, is there any solution to this issue? Why aren't these constructors generated unconditionally?

The reason for the current implementation (jOOQ 3.10.0) is to prevent "excessive" code generation in cases where there are only few foreign key constraints in a large schema. I.e. there's only little gain in having this limitation.
The fact that there are compilation errors in generated code in your setup hints that this limitation is effectively wrong. It should be removed again from jOOQ 3.12.0 and 3.11.1:
https://github.com/jOOQ/jOOQ/issues/7573
A workaround could be to generate all schemas and remove the unwanted code using a post-processor.

Related

Which JPA key generator option to choose?

I am new to JPA and databases in general. I was trying to generate entities from tables using JPA tools in Eclipse. There are a number of tables and I am trying to generate entities for all of them at the same time. The JPA tool gives me the following options for Key-generator.
I looked around on Google a bit but could not find much that addresses all the options. What do the options mean?
The JPA specification document provides answers in section 11.1.20, on pages 449 and 450:
The GeneratedValue annotation provides for the specification of
generation strategies for the values of primary keys. The
GeneratedValue annotation may be applied to a primary key property or
field of an entity or mapped superclass in conjunction with the Id
annotation.
The use of the GeneratedValue annotation is only required to be
supported for simple primary keys.
In case you are not familiar with the Id annotation, here is a quick explanation by Vlad Mihalcea from t/his blog post:
The #Id annotation is mandatory for entities, and it must be mapped to
a table column that has a unique constraint. Most often, the #Id
annotation is mapped to the Primary Key table column.
The types of primary key generation are defined by the GenerationType enum:
TABLE, SEQUENCE, IDENTITY, AUTO
The JPA spec gives details on those types as follows:
The TABLE generator type value indicates that the persistence provider
must assign primary keys for the entity using an underlying database
table to ensure uniqueness.
The SEQUENCE and IDENTITY values specify the use of a database
sequence or identity column, respectively. The further specification
of table generators and sequence generators is described in sections
11.1.48 and 11.1.51.
The AUTO value indicates that the persistence provider should pick an
appropriate strategy for the particular database. The AUTO
generation strategy may expect a database resource to exist, or it may
attempt to create one. A vendor may provide documentation on how to
create such resources in the event that it does not support schema
generation or cannot create the schema resource at runtime.
A well-established and recommended strategy is to chose the SEQUENCE strategy, if that is supported by the database management system.
Note well, that strictly speaking, there is no NONE strategy defined in the JPA spec. The corresponding option in the select one menu, depicted in the screenshot, simply expresses that "none" of the four regular types shall be set. This seems to be a fallback to indicate you don’t have chosen your strategy for now. Still, you should pick one from the regular ones.

#RawQuery and Generated RxRoom.createFlowable(db, tables)

I'm using RxJava2 and Android's Room framework (v2.1.0). Ultimately, I'm using the Flowable from a #RawQuery-annotated abstract method in my #Dao class. When I updated a row/column of one of the referenced tables (using an #Update method in my #Dao on the root entity), I was expecting the Flowable to re-trigger when any of the referenced tables in the #RawQuery were touched. However, that didn't seem to be the case.
After digging into the generated code for my #Dao class, I noticed that the Room return value is wrapped in a call to RxRoom::createFlowable. I noticed that the tableNames argument only contained a subset of the expected tables names, so it made more sense why my Flowable was not re-triggering since I had updated one of the tables outside of the specified subset.
Upon further reflection, it made more sense why the code generator for Room couldn't derive the full set of table names, since all the table names were only available at runtime. (I wish the RxRoom documentation made it more plainly obvious that observing a #RawQuery would be flaky w/o using the observedEntities annotation argument!)
However, it's still a mystery to me how that subset of table names was even generated. While I probably could dive into the code base, it'd be great if someone knowledgeable could summarize how RxRoom derives the table names from a #RawQuery. My guess is that RxRoom is using the "leaf" joined tables of the root entity being queried, but I don't really understand why that's a reasonable default. IMHO, a safer default would be to NOT observe any referenced tables in a #RawQuery unless observedEntities is specified.

How can i use one sequence to auto increment several tables in squeryl (PostgreSQL)?

I have follows
val s1 = autoIncremented("advert_id_seq")
on(car)(attributes => declare(attributes.id is (s1)))
on(danceInstructor)(attributes => declare(attributes.id is (s1)))
When i run my app a catch following exception
org.postgresql.util.PSQLException: ERROR: relation "advert_id_seq" already exists
As i realized, squeryl try to create sequence twice and gets error
I'm guessing that your issue is with Schema generation, not with querying the database. If that's the case, then you probably just want to avoid having Squeryl create the tables directly. Squeryl's schema generation is purposefully basic. When you outgrow what it can do I think you're better off adopting some method that gives you greater control than a "read your model and generate stuff" tool can offer. Tools like Flyway or Liquibase are good for this.
If you don't want to adopt a new library you can also use Squeryl to output the schema to a file through one of the Schema.printDdl methods then remove the extraneous sequence before executing it.
Ruby on Rails has a polymorphic association, but scala active record don't have its. I made something like it's, and will push it in github repo.

Change Fluent API mapping dynamically

Our project uses Entity Framework Code First. We wish to have an instance where a very simple POCO represents many tables in the database. It is part of a horizontal partitioning strategy in SQL Azure. SQL Azure does not support file groups, thus it does not support typical partitioning. There are going to be a very large numbers of tables, so using a UNION ALL view as a partitioned view via CHECK CONSTRAINTs on the base tables will not be feasible.
Thus, we would prefer to peform the mapping as needed at runtime. However, this occurs in the OnModelCreating event of the DbContext class via code such as
modelBuilder.Entity<EntityName>().ToTable("foo", "bar");
. Is it possible for us to perform this mapping inside a factory? We would prefer to supply metadata to the factory and have it use the Fluent API then, rather than have a one-to-one mapping between POCO and table via the ModelBuilder.
You can add a constructor to your DbContext derivative, having two string arguments for table name and metaschema name. You can store the names in member variables and use them in the ToTable method.
The DbModel is created when it is actually needed, so the constructor always runs before the OnModelCreating event. (This is not always the case in derived classes, but that's a different topic).
As an optimization you can cache compiled DbModels and build DbContexts by the constructor accepting a DbCompiledModel.

How can I leverage JPA when code is generated?

I have classes for entities like Customer, InternalCustomer, ExternalCustomer (with the appropriate inheritance) generated from an xml schema. I would like to use JPA (suggest specific implementation in your answer if relevant) to persist objects from these classes but I can't annotate them since they are generated and when I change the schema and regenerate, the annotations will be wiped. Can this be done without using annotations or even a persistence.xml file?
Also is there a tool in which I can provide the classes (or schema) as input and have it give me the SQL statements to create the DB (or even create it for me?). It would seem like that since I have a schema all the information it needs about creating the DB should be in there. I am not talking about creating indexes, or any tuning of the db but just creating the right tables etc.
thanks in advance
You can certainly use JDO in such a situation, dynamically generating the classes, the metadata, any byte-code enhancement, and then runtime persistence, making use of the class loader where your classes have been generated in and enhanced. As per
http://www.jpox.org/servlet/wiki/pages/viewpage.action?pageId=6619188
JPA doesn't have such a metadata API unfortunately.
--Andy (DataNucleus)