简体   繁体   English

从数据库中检索一个值并将其设置为 Spring boot 中的 @Table Name 值

[英]Retrieve a value from Database and set it as @Table Name value in Spring boot

I have a Class with @Table annotation, currently I directly set the Name value like this :我有一个带有@Table注释的类,目前我直接设置 Name 值是这样的:

@Data
@Entity
@NoArgsConstructor
@Table(name = "US_STUDENTS" )
public class Student {

// some properties

}

I have a table in DB named MasterCountries which have a Column name - value = countryPrefix - "US_"我在数据库中有一个名为MasterCountries的表,它有一个列名- value = countryPrefix - "US_"

When the Spring boot app run, I want to take this data from the DB and use it as part of the @Table name value to make it like this :当 Spring boot 应用程序运行时,我想从数据库中获取这些数据并将其用作 @Table 名称值的一部分,使其像这样:

@Data
@Entity
@NoArgsConstructor
@Table(name = countryPrefix + "STUDENTS" ) // so the end result will be "US_STUDENTS"
public class Student {

// some properties

}

I've google'd and still have not found a solution to this, the reason is because I want to make it dynamic, whenever this spring boot service need to be redeployed for other country, just need to retrieve the specific countryPrefix from the DB, so no need to change the code again for each country Deployment.我已经用谷歌搜索过,但仍然没有找到解决方案,原因是我想让它动态化,每当需要为其他国家/地区重新部署此 Spring Boot 服务时,只需要从数据库中检索特定的 countryPrefix ,因此无需为每个国家/地区部署再次更改代码。

for the repository I set up an interface that extends JpaRepository as shown below :对于存储库,我设置了一个扩展 JpaRepository 的接口,如下所示:

public interface MasterCountriesRepository extends JpaRepository<CountriesSetting, Long> {

    CountriesSetting findByCountryCode(String countryCode);

}

and for the CountriesSetting entity :对于CountrySetting实体:

@Data
@Entity
@NoArgsConstructor
@Table(name = "MasterCountries" )
public class CountriesSetting {

// some properties

}

Is this possible to achieve in spring JPA ?这可以在 spring JPA 中实现吗? please ignore any mistype or minor syntax problem, as this is not the real code.请忽略任何错误输入或轻微的语法问题,因为这不是真正的代码。 Thanks in advance.提前致谢。

Annotations require that everything involved in their usage is a compile time constant.注释要求其使用中涉及的所有内容都是编译时常量。 That's by java spec, you can't ask the compiler to forget about that restriction just for a moment.那是java规范,你不能让编译器暂时忘记这个限制。

Any expression is a 'compile time constant' if it is:任何表达式都是“编译时常量”,如果它是:

  • A literal... but null doesn't count!一个字面量……但null不算数!
  • Of the form X ! Y形式X ! Y X ! Y where X and Y are 'compile time constant', and ! X ! Y其中 X 和 Y 是“编译时间常数”,并且! is some operator, such as + or -.是一些运算符,例如 + 或 -。
  • A reference to a field which is [A] static, [B] final, [C] whose type is String or primitive, [D] whose initializing expression is 'compile time constant' (using this same definition, recursively).对字段的引用,该字段为 [A] 静态、[B] 最终、[C] 其类型为String或原始类型、[D] 其初始化表达式为“编译时常量”(使用相同的定义,递归)。

Thus, Foo.x is compile time constant given:因此, Foo.x是给定的编译时间常数:

class Foo {
   static final int x = 5 - 3 + Integer.MAX_VALUE - Bar.y;
}
class Bar {
   static final int y = 10;
}

but these aren't:但这些不是:

  • static final long z = System.currentTimeMillis();
  • static final String y = null;
  • static final String a = LocalDate.of(2020, 1, 1).toString();

Note that the third seems constant (the output of that expression is set in stone and will be the same on all VMs, forever), and yet doesn't count, as it isn't explicitly named in the java lang spec.请注意,第三个似乎是恒定的(该表达式的输出是一成不变的,并且在所有 VM 上永远相同),但不算数,因为它没有在 java lang 规范中明确命名。

Given that you want to retrieve this from the database, what you want is impossible - as surely your intent is that the table name is not locked in during compilation, and yet the reason why the expression you feed to an annotation param must be compile time constant is that the compiler must lock it in.鉴于您想从数据库中检索它,您想要的东西是不可能的——当然,您的意图是在编译期间表名没有被锁定,但您提供给注释参数的表达式的原因必须是编译时常量是编译器必须将其锁定。

So what is the solution?那么解决方法是什么呢?

Don't use the annotations.不要使用注释。 Annotations that are queried at runtime are usually a configuration shortcut.在运行时查询的注解通常是配置快捷方式。 Generally there is a more roundabout way to achieve the same goal, calling APIs which default to 'I shall just read out the annotation value'.通常有一种更迂回的方式来实现相同的目标,调用默认为“我将只读出注释值”的 API。

Annotations can also be queried at compile time - lombok does that, as do Annotation Processors (eg processors that produce XML-based config files during your compilation run).也可以在编译时查询注释 - lombok 可以这样做,注释处理器也是如此(例如,在编译运行期间生成基于 XML 的配置文件的处理器)。 Trivially it should be obvious to you that your entire plan cannot possibly work then - these are fundamentally 'at compile time' concepts.很明显,你的整个计划不可能在那时运行 - 这些基本上是“在编译时”的概念。

Simpler suggestion更简单的建议

Thinking out of the box, perhaps:开箱即用,也许:

Have a separate script that will run a CREATE OR REPLACE VIEW statement that creates a view with a singular name (just Students for example), that just mirrors a stated table (Such as US_Students ), using ON INSERT and ON UPDATE and ON DELETE to also 'pass through' any attempt to insert/update/delete attempts on this view to end up affecting the US_Students table.有一个单独的脚本将运行CREATE OR REPLACE VIEW语句,该语句创建一个具有单数名称的视图(例如,仅Students ),该视图仅反映指定的表(例如US_Students ),使用ON INSERTON UPDATEON DELETE到还“通过”任何在此视图上插入/更新/删除尝试以最终影响US_Students表的US_Students

To 'change' the 'country', just run that script one-off and restart the java app, and voila.要“更改”“国家/地区”,只需一次性运行该脚本并重新启动 Java 应用程序,瞧。

How to make views and have them work with delete/insert/update depends on your DB engine.如何制作视图并使它们与删除/插入/更新一起工作取决于您的数据库引擎。 In both MySQL and postgres, a basic view on a simple SELECT without aggregates and joins and such 'just works'.在 MySQL 和 postgres 中,一个没有聚合和连接的简单SELECT的基本视图,这样的“正常工作”。

You're really just looking at:你真的只是在看:

CREATE OR REPLACE VIEW Students AS SELECT * FROM US_Students;

run that single statement and you're good to go.运行那个单一的语句,你就可以开始了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM