Apache Cayenne:将固定与动态提供的 DataMap 合并到一个 ServerRuntime

Posted

技术标签:

【中文标题】Apache Cayenne:将固定与动态提供的 DataMap 合并到一个 ServerRuntime【英文标题】:Apache Cayenne: Merging fixed with dynamically supplied DataMaps into one ServerRuntime 【发布时间】:2018-07-16 13:08:56 【问题描述】:

我的应用程序设计包含固定和动态 DataMap 以连接到不同的 (Oracle) 数据库实例/用户。为简单起见,我确实将它们分成了两个不同的 Cayenne 项目。

    使用固定的 DataMap 创建 ServerRuntimeBuilder,构建和查询我的客户表。

    对于每个客户,使用第二个 ServerRuntimeBuilder 加载动态 DataMap,并进行必要的修改(更改名称和默认模式):

    ...
    List<Customer> allCustomers = Customer.allCustomers(this.cayenneRuntime1.newContext());
    for (Customer customer : allCustomers) 
        final String dbPrefix = customer.getDbprefix();
    
        ServerRuntimeBuilder builder = ServerRuntime.builder();
        // load and modify DataMap
        builder.addConfig("ApacheCayenne/Data/cayenne-dynamicDomain.xml");
        builder.addModule(binder -> 
            binder.bind(DataMapLoader.class).to(MyDataMapLoader.class);
            ServerModule.contributeProperties(binder).put("CUSTOMER_PREFIX", dbPrefix);
        );
        ServerRuntime cayenneRuntime2 = builder.build();
        LOG.info("Initialized customer model " + customer + " prefix: " + customer.getDbprefix());
        // TODO Merge with cayenneRuntime1?
    
    
    
    public class MyDataMapLoader extends XMLDataMapLoader   
        @Inject
        private RuntimeProperties properties; 
        @Override
        public DataMap load(Resource configurationResource) throws CayenneRuntimeException 
            DataMap map = super.load(configurationResource);
            // Dynamically set name and default schema to map
            String dbPrefix = properties.get("CUSTOMER_PREFIX");
            map.setName(customer1.dbPrefix + "...")
            map.setDefaultSchema(customer1.dbPrefix + "...")
            return map;
        
    
    

另外还有一个自己的 ConfiguredDataSource 实现,它负责 JDBC 连接 URL 和凭据。到目前为止,这部分工作正常。

我的问题:通过这种设计,我最终为每个客户提供了 1 + n 个 ServerRuntimes。但最后我想要一个单一的ServerRuntime

a) 是否可以将这些 ServerRuntime 与 Cayenne 4.0RC1 功能和未来版本即时合并?

b) 我是否需要在cayenne-project 库的帮助下阅读动态地图,如here 所述。修改每个动态项目并将其存储到文件系统。在处理完我的所有客户后,使用所描述的方式使用 ExecutingMergerContext 或 Merging Multiple Projects?

创建一个包含所有 Cayenne 项目的最终 ServerRuntime
ServerRuntime runtime = ServerRuntime.builder()
    .addConfig("com/example/cayenne-fixed-project.xml")
    .addConfig("org/foo/cayenne-dynamic-Customer1.xml")
    .addConfig("org/foo/cayenne-dynamic-Customer2.xml")
    .build();

提前感谢您帮助我。

【问题讨论】:

【参考方案1】:

我会启动 runtime1 以获取配置数据,然后创建包含固定和动态映射的 runtime2,以及用于动态重写名称和架构的自定义 DataMap 加载器:

ServerRuntime runtime2 = ServerRuntime.builder()
  .addConfig("com/example/cayenne-fixed-project.xml")
  .addConfig("org/foo/cayenne-dynamic-Customer1.xml")
  .addConfig("org/foo/cayenne-dynamic-Customer2.xml")
  .addModule(..)
  .build();

当你完成时不要忘记关闭 runtime1,这样你最后只会有一个运行时。

【讨论】:

非常感谢。使用 Modules 和 DI 为动态 DataMap(它们相应的 DataNodeConfig)正确设置连接凭据有点棘手。 binder.bind(DataChannelDescriptorLoader.class).to(MyDataDomainProvider.class); binder.bind(DataMapLoader.class).to(MyDataMapLoader.class);并注入一个自己的 ConfigurationInfo 持有者实例,对我有用。

以上是关于Apache Cayenne:将固定与动态提供的 DataMap 合并到一个 ServerRuntime的主要内容,如果未能解决你的问题,请参考以下文章

Apache Cayenne“类未与 Cayenne 映射”

我可以将 Cayenne 配置为使用提供程序来获取模型的新实例吗?

Apache-Cayenne 自定义查询结果

使用 Apache Cayenne 批量插入数据库表

Apache Cayenne:java.io.StreamCorruptedException

Apache Cayenne:处理 Postgresql 枚举类型