从关系数据库中加载实体时,只有部分表结构已知时,如何操作?

huangapple go评论75阅读模式
英文:

How do I load an entity from a relational DB when only part of the table schema is known in advance?

问题

我有一个实体映射到一个表。这个表通常在映射的属性之上还有一些列。例如,如果实体定义如下:

@Entity
class MyEntity {
  private String a;
}

那么表中将有列 a。在一个模式中,它还可能有列 bc,在另一个模式中可能有 def 列。我以为可以简单地重写 EntityManagerload 方法来加载在 MyEntity 中定义的所有属性,然后将所有其他属性加载到 Map<String, Object> 中,但我找不到实现这一点的方法。

到目前为止,我考虑过以下方法:

  1. 我找到了这个 SO 问题,它导致了这篇文章,也许解决了这个问题,但需要在启动时加载映射,这不解决我的问题,因为我不断地在不同模式之间切换,因此需要一遍又一遍地重新加载映射。
  2. 重写RelationalMappingContext 也假定了一个固定的模式。
  3. 应该有一种方法来提供 EntityManager 作为一个 bean,但我找不出如何做,而且我不确定它是否会遇到与 1 和 2 相同的问题。
  4. 我可以通过字节码操作进行一些复杂的操作,但这将需要针对每个模式拥有一个实体,这太复杂了。
  5. 所以,我被迫考虑重写 CrudRepository 中的所有方法并提供自己的实现。这将非常繁琐和难以维护。

还有其他的想法吗?

英文:

I have an entity mapped to a table. This table usually has some columns on top of the mapped properties. For example if the entity is defined as:

@Entity
class MyEntity {
  private String a;
}

Then the table has column a. In one schema it may also have columns b and c, in another d, e and f. I thought it would be simple to override EntityManager's load method to load all the properties defined in MyEntity and subsequently load all the others into a Map&lt;String, Object&gt;, but I can't find a way to do it.
Here's what I considered so far:

  1. I found this SO question, which led to this post which maybe solves the issue but requires loading the mapping on startup, which doesn't solve my problem since I'm constantly switching between schemas and therefore would have to reload the mapping over and over.
  2. Overriding RelationalMappingContext also assumes a constant schema.
  3. There should be a way to supply EntityManager as a bean but I can't figure out how and I'm not sure if that wouldn't run into the same issues as 1 & 2.
  4. I can do something complicated with bytecode manipulation but this would require having an Entity per schema, which is too complicated.
  5. So I'm forced to consider overriding all methods in CrudRepository and providing my own implementation. That would be very hacky and unwieldy.

Any other ideas?

答案1

得分: 0

  1. 使用 NoSQL 数据库:如果需要动态和频繁地添加列,您可以考虑使用支持动态模式的 NoSQL 数据库。NoSQL 数据库如 MongoDB 设计用于处理动态数据,允许您存储文档或键值对而不强制执行固定的模式。

  2. 使用 JSON 或 XML 列:一些数据库,如 PostgreSQL 或 MySQL,支持存储半结构化数据的 JSON 或 XML 列。您可以将动态数据存储为 JSON 或 XML 文档在单个列中,并使用 SQL 或类似 NoSQL 的查询来查询它们。

例如,如果您正在使用 PostgreSQL,您可以像这样在 my_table 表中定义一个 JSON 列:

ALTER TABLE my_table ADD COLUMN dynamic_data jsonb;

然后,您可以将 JSON 文档插入到 dynamic_data 列中,并使用 PostgreSQL 的 JSON 函数来查询它们。

另外,您还可以使用 Hibernate 的 @Type 注解将 JSON 或 XML 列映射到 Java 对象。例如:

@Entity
@Table(name = "my_table")
public class MyEntity {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;

   @Type(type = "jsonb")
   @Column(columnDefinition = "jsonb")
   private Map<String, Object> dynamicData;

}
英文:

you have two Option in this situation

  1. Use a NoSQL database: If you need to add columns dynamically and frequently, you might consider using a NoSQL database that supports dynamic schemas. NoSQL databases like MongoDB is designed to handle dynamic data and allow you to store documents or key-value pairs without enforcing a fixed schema.

  2. Use a JSON or XML column: Some databases like PostgreSQL or MySQL support JSON or XML columns that can store semi-structured data. You can store your dynamic data as a JSON or XML document in a single column and query it using SQL or NoSQL-like queries.

For example, if you are using PostgreSQL, you can define a JSON column in your my_table table like this:

ALTER TABLE my_table ADD COLUMN dynamic_data jsonb;

You can then insert JSON documents into the dynamic_data column and query them using PostgreSQL's JSON functions.

Alternatively, you can use Hibernate's @Type annotation to map a JSON or XML column to a Java object. For example:

@Entity
@Table(name = &quot;my_table&quot;)
public class MyEntity {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;

   @Type(type = &quot;jsonb&quot;)
   @Column(columnDefinition = &quot;jsonb&quot;)
   private Map&lt;String, Object&gt; dynamicData;

}

答案2

得分: 0

最后我选择了Spring AOP。切点拦截每个使用自定义注解装饰的存储库方法。当这种情况发生时,切点方法会发出另一个SELECT *查询(在读取的情况下),并填充实体的附加属性。

英文:

In the end I went with Spring AOP. The cutpoint intercepts every repository method decorated with a custom annotation. When that happens the cutpoint method issues another query of SELECT * (in the case of reads) and populates the entity with the extra properties.

huangapple
  • 本文由 发表于 2023年3月20日 23:11:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/75792048.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定