GORM 关联查询用法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GORM 关联查询用法相关的知识,希望对你有一定的参考价值。

参考技术A 以查询用户列表, 以及用户的详情 , 文章为例
定义结构体

跨两个数据源的 Grails GORM 域关联

【中文标题】跨两个数据源的 Grails GORM 域关联【英文标题】:Grails GORM domain association across two datasources 【发布时间】:2013-09-17 02:23:30 【问题描述】:

如果另一个域类使用不同的数据源,是否可以在两个域类(即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"
    

【问题讨论】:

您可以通过here 和here 为非关联域找到一条出路,但我非常怀疑您是否可以使用hasManybelongsTo 来做同样的事情。 【参考方案1】:

正如@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 实例及其相关项目的引用,所以这个解决方案应该对我有所帮助。它仍然优于必须在域类之外执行链接逻辑,这是另一种选择。【参考方案2】:

如果有人想要更“自动化”的东西(如果适用的话),我想出了另一个解决方案,也许它会对性能产生影响,但如果你像我一样使用 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”【参考方案3】:

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

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。

【讨论】:

以上是关于GORM 关联查询用法的主要内容,如果未能解决你的问题,请参考以下文章

Grails GORM 查询以匹配多个关联对象

GORM关联查询

gorm中的关联查询

Gorm 预加载及实现联表条件查询仿WhereHas

Gorm 预加载及实现联表条件查询仿WhereHas

thinkphp5 的 belongsToMany 多对多关联用法