Closed homedirectory closed 1 year ago
Initial approach that makes use of instantiation of generic types through reflection
Generate a static method in the MetaModels
class that would have the following signature:
public static <T extends EntityMetaModel> T withAlias(String alias, T metaModel)
Then by using reflection it would be possible to instantiate T
with the given alias
. This approach, although the implementation is not the simplest, would be very convenient. Consider that it may be used like this:
String alias = "t";
var timesheet = MetaModels.withAlias(alias, MetaModels.TimeSheet_);
select(Timesheet.class).as(timesheet.alias).where().prop(timesheet.person())
Generation of a static method for each meta-model
Generate a method withAlias(String)
as a static method for each meta-model. Every meta-model would provide its own implementation to ensure that the correct type is returned. The method must be static, in my opinion, in order to avoid causing a potential conflict that would arise if the underlying entity had a property withAlias
. In general, it is preferred to limit all instance methods of a meta-model only to those that model the properties of the underlying entity.
String alias = "t";
TimeSheetMetaModel timesheet = TimeSheetMetaModel.withAlias(alias);
select(Timesheet.class).as(timesheet.alias).where().prop(timesheet.person())
While keeping this in mind, I think that it would still be best to extend the MetaModels
class for it to remain the sole interface to meta-models, preserving the simplicity.
An interesting approach was proposed by @01es to change the way meta-model instances are accessed in the MetaModels
class. The idea is to use method calls instead of static fields. So instead of having this:
public static final PersonMetaModel Person_ = new PersonMetaModel();
The following would be generated:
public static PersonMetaModel Person_() {
return new PersonMetaModel();
}
public static PersonMetaModel Person_(String alias) {
return new PersonMetaModel(alias);
}
The non-aliased meta-model should be computed lazily to avoid creating multiple instances that are identical.
Yes, so the invocation would look like this:
var alias = "t";
var timesheet = TimeSheet_(alias);
select(Timesheet.class).as(alias).where().prop(timesheet.person())...
or
var alias = "t";
select(Timesheet.class).as(alias).where().prop(TimeSheet_(alias).person())...
Description
Database queries are often constructed with the usage of aliases, which requries prepending the alias to every column name that is referenced in a query (
"alias.column"
). Entity meta-models, however, provide no ability to add an alias to the constructed dot-notated path. This forces software engineers to rely on String concatenation, which should ultimately be disallowed (or discouraged, at least). For example, currently the following approach is used to combine meta-models and aliases:Expected outcome
MetaModels
class should have a static method for each meta-model that accepts one argument -- an alias. The returned value should be cached for further use (i.e. lazily computed).EntityMetaModel
should be extended with a public fieldalias
that would store the alias it was instantiated with, otherwise it should benull
.EntityMetaModel
(i.e. generated meta-models) should provide a static factory methodwithAlias(String)
Consider the following example:
Accessing a meta-model without an alias should remain as it were, through a static field.
Alternative approaches are discussed in the comments below.