Grails GORM领域关联跨越两个数据源

9
两个领域类(即belongsTo)之间是否可以建立关联,如果另一个领域类使用了不同的数据源?两个数据源也是不同的数据库驱动程序。我怀疑这可能是不可能的,但我想在这里向社区寻求帮助以确定是否有可能。目前,我正在尝试这样做,但是我遇到了通常的Hibernate错误:Invocation of init method failed; nested exception is org.hibernate.MappingException: An association from the table domain_class_A refers to an unmapped class: DomainClassB。示例:
class DomainClassA {
    static belongsTo = [dcB: DomainClassB]

    static mapping = {
        datasource "ds1"
        table name: "domain_class_A", schema: "schema_A"
    }
}

class DomainClassB {
    static hasMany = [dcA: DomainClassA]

    static mapping = {
        datasource "ds2"
        table name: "domain_class_B", schema: "schema_B"
    }
}

你可以按照这里和这里提到的方法(http://grails.1312388.n4.nabble.com/Grals-2-0-0-Multiple-Datasources-error-td4584075.html 和 http://grails.1312388.n4.nabble.com/Associations-across-databases-td4641257.html)来解决非关联域的问题,但我非常怀疑你能否使用 hasManybelongsTo 来实现相同的效果。 - dmahapatro
3个回答

8
正如 @dmahapatro 在评论中指出的那样,这与1元素情况类似,创建自己的方法来管理关系是正确的方式。这也与我之前关于映射集合性能问题的演讲有关,所以你可以一举两得:http://www.infoq.com/presentations/GORM-Performance 如果你不需要集合,即你只使用它来添加子对象的新实例,则这将起作用,因为 DomainClassB 实例的 get 调用将使用其数据源:
class DomainClassA {
   Long domainClassBId
   private DomainClassB dcB

   DomainClassB getDomainClassB() {
      if (!dcB && domainClassBId) {
         dcB = DomainClassB.get(domainClassBId)
      }
      dcB
   }

   void setDomainClassB(DomainClassB dc) {
      domainClassBId = dc.id
   }

   static transients = ['domainClassB']

   static mapping = {
      datasource "ds1"
      table name: "domain_class_A", schema: "schema_A"
   }
}

class DomainClassB {

    static mapping = {
        datasource "ds2"
        table name: "domain_class_B", schema: "schema_B"
    }
}

创建一个新的DomainClassA实例与传统的addTo...方法有所不同,但也不难:

DomainClassB dcb = ...
def dca = new DomainClassA(domainClassBId: dcb.id)
dca.save()

如果您想访问一个 DomainClassB 的所有 DomainClassA 实例,您可以添加一个方法:

Set getDomainClassAs() {
   DomainClassA.findAllByDomainClassBId(id)
}

但是由于您自己进行查询,如果您只需要其中的一些实例,则不必加载所有实例,因此您可以进行任何想要的查询。


这似乎是我即将采取的路线,但我只是想确认一下是否有任何Grails / GORM魔法可以为我完成这些工作,而我却忽略了它。我只需要DomainClassA提取对DomainClassB实例及其相关项目的引用,因此这个解决方案应该会对我有所帮助。这仍然比在域类之外进行关联逻辑要好,这是另一种替代方案。 - Thomas Farvour

0
如果有人想要更"自动化"的解决方案,我又有了另一个方法,也许会影响性能,但特别是在像我这样使用MongoDB for Grails插件的情况下,使用本机Java API获取文档有时是必要的。
我所做的是,在DomainA中使用beforeValidate()来分配domainClassBId的值,并使用onLoad()来分配dcB的值。通过这种方式,流程将更加自然,符合Hibernate的使用习惯。当保存DomainA时,将分配一个DomainB到DomainA中,并且onvalidate代码将只持久化相应数据源的ID。当你加载对象,例如使用DomainA.find()方法时,onLoad代码将确保返回的对象具有DomainB类型的属性,而不是Long类型,这样你就可以用它来查询数据库。基本上,这是Burt Beckwith之前标注的相同方法,但在保存和加载DomainA方面更简单。再次声明我不确定是否存在性能问题,希望有更多经验的人能够帮助我们。

我遇到了一个错误:"表domain_class_a中的关联引用了一个未映射的类:com.example.DomainClassB"。 - Michal_Szulc

0

配置你的数据库以在两个数据库之间创建DB-Link,然后你可以执行类似以下的操作:假设你在指向数据库2的数据库1中有一个名为database2link的DB Link,那么你的查询将如下所示。

select * from domain_class_A tb inner join domain_class_B@database2link tb2 on tb.domain_class_B_Id=tb2.id

通过在映射表名中提供@database2link,你可以映射DomainClassB。

static mapping = {
    datasource "ds1"
    table name: "domain_class_B@database2link", schema: "schema_B"
}

请注意,我们仅使用数据源ds1。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接