如何扩展不可修改的模型以用于JPA?

时间:2019-05-07 18:19:28

标签: java hibernate spring-boot spring-data-jpa persistence

为来自不可修改的依赖关系的数据模型创建持久性(例如通过Spring Boot或仅通过JPA或Hibernate本身)的最佳实践是什么?典型的局限性如无法覆盖字段或Decorator之类的模式允许什么,以及哪些不会减慢我的进度。我尝试了一些事情,但最终总是得到以下结果:要么修改源模型(例如添加注释以使其与本机兼容->我不想要的fork),要么编写大量包装器代码这样会过多地复制原始模型-但这甚至无法正常工作:

我尝试了

  • 为原始课程创建一个JpaRepository。不起作用,因为将扩展类强制转换为其父类无效。
  • 使用可获取必要注释(例如@Entity)的自定义类扩展原始类,可以在此类存储库中使用。但是这里的问题是
    • 原始类缺少@Id注释,可以通过在扩展类中使用新的ID来解决此问题,但是
    • 给定的模型还具有非简单的体系结构,包括作为模型本身一部分的其他类的列表。因此可能需要其他注释,例如@ElementCollection,因为不能覆盖字段,所以不能添加这些注释。
      • 在新类中创建具有相同名称的新字段来隐藏它不起作用:
      • 类似Could not determine type for: java.util.List, at table: yeah_this_one, for columns:[org.hibernate.mapping.Column(objects)]的错误表明无法完全隐藏原始字段(更改了新类中的表名和列名以进行验证)。
      • 因此,当然添加@ElementCollection(据说可以解决此问题)也无济于事。
    • @AttributeOverride也无法覆盖注解来设置ID或其他设置,只能更改名称和列。

我一直处于这种状态,想知道这是否是正确的方法。

根据我的理解设置或期望的工作方式:

总体思路是基于这个Spring Boot REST tutorial,我尝试使用依赖项中的模型对其进行扩展。

我们假设存在不可修改的依赖项中的原始模型类ModelModelEntity将是扩展类,用作将模型引入Spring持久性的方式。

在依赖项的范围内,原始类将是:

// Given dependency, not modifiable
@Some existing annotation
public class Model extends AnotherClassFromDep {

    @more annotations
    private IdLikeClassFromDep modelId;

    //more complex attribute
    @Nullable
    private List<RefClassFromDep> objects = new ArrayList<>();

    // more attributes, getter, setter etc.
}

在我的程序范围内:

结合少量orm.xml,可以将原始Model注释为MappedSuperclass,而无需修改(根据https://stackoverflow.com/a/2516951/1844976)。

<?xml version="1.0" encoding="UTF-8"?>

<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0">
    <mapped-superclass class="package.name.of.original.Model">

    </mapped-superclass>
</entity-mappings>

这允许创建这样的类,该类扩展了原始POJO模型以添加JPA注释:

@Entity
public class ModelEntity extends Model {

    // some @Id attribute is necessary, which should correspond to
    // the already existing ID attribute from the original `Model`
    // in the best case, but an additional one would work too
    private @Id @GeneratedValue Long id;

    // Different approaches to solve the List error from above, for
    // instance hiding the original attribute
    @ElementCollection
    private List<RefClassFromDep> objects;

    public ModelEntity(){
        super();
    }

}

在当前状态下,这些问题使我无法继续前进。但是,我完全希望它可以与JpaRepository一起使用:

// of course, creating a JpaRepository with original `Model` wouldn't
// work, because it has no `@Entity`
public interface ModelRepository extends JpaRepository<ModelEntity, IdLikeClassFromDep> {
}

以一种可能的方式实际访问它:

@Configuration
public class LoadDatabase {

    @Bean
    CommandLineRunner initDatabase(ModelRepository modelRepository) {
        return args -> {
            // depending on the implementation above, either create a 
            // Model and cast it or directly create a ModelEntity, set
            // attriubtes and save it through the JpaRepository
            modelRepository.save(model);
        };
    }
}

更抽象和更具体的与代码相关的想法和评论都将对我有所帮助。谢谢!

1 个答案:

答案 0 :(得分:1)

过去,Jpa / Hibernate是通过XML配置的。 您需要提供git push repo1 +master:branch1 进行常规配置。在此文件中,您添加了persistence.xml标记,该标记指向另一个文件<mapping-file>。在该文件中,您为实体配置了映射(这些天通过JPA批注完成)。

请参见https://vladmihalcea.com/how-to-use-external-xml-mappings-files-outside-of-jar-with-jpa-and-hibernate/

尽管上述方法被认为是旧方法,但仍支持它们。 orm.xml的方法LocalContainerEntityManagerFactoryBean允许您指向setMappingResources文件。搜索路径和默认位置有些时髦,但有据可查: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/jpa/LocalContainerEntityManagerFactoryBean.html#setMappingResources-java.lang.String...-

请注意,您以此方式配置的第三方类需要符合Java Bean约定(无参数构造函数,getter和setter)