【问题标题】:dynamic joincolumn and join clause with variables带变量的动态连接列和连接子句
【发布时间】:2014-02-18 06:47:45
【问题描述】:

我有一个单向的一对一关系。我想要实现的是

  • 使用 CASE 创建一个 join on 子句并向其发送变量,以便我可以更改联接列(也欢迎任何其他更改联接列的建议)
  • 忽略 hibernate 创建的第一个子句,并使用问题底部的条件创建特定的 ON 子句。

我在 SQL 管理器中的查询:

SELECT d.Description, d.AccountId, d.PartnerId, a.FormattedName FROM 
InvoiceDesigns d 
INNER JOIN UserAccount a
ON 
    a.id =
    CASE 
        WHEN d.PartnerId != -1 AND d.AccountId = 1 THEN d.PartnerId
        WHEN d.PartnerId = 1 THEN d.AccountId 
        ELSE 1
    END
WHERE
d.AccountId = 1 OR PartnerId = 1

工作查询在 SQL 管理器中运行,而不是在 hibernate 中。这是我想要实现的目标,我希望 hibernate 创建这样的查询。
当一个帐户(假设 ID = 1 继续举例)显示他们将看到的设计时
A) 设计的 PartnerId 不是 -1 AND AccountId 为 1,这意味着它是由该帐户的合作伙伴,并将显示合作伙伴的格式化名称。
这适用于查看可用设计时的普通帐户。如果合作伙伴为他们创建了设计,他们将看到该合作伙伴的名称。

B) PartnerId 等于账户的ID,表示它是一个合作伙伴设计,并且将显示创建的账户相关设计的formattedName。
这是供合作伙伴帐户查看他们创建的设计。

C) 设计由帐户直接创建,因此会显示自己的名称。适用于普通帐户和自行创建的设计。

当我只想使用 AccountId 或 PartnerId 但我需要更改列以获取相关的 FormattedName 时,正常加入在休眠中工作正常。我尝试了@Where、@Filter、@JoinColumnOrFormula,但无法实现此查询。

我的@Where 类基本上是这样的:

设计类:

@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    int id;

    @Column(name="AccountId")
        int accountId;

    @Column(name="PartnerId")
        int partnerId;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "AccountId", referencedColumnName = "id", insertable = false, updatable = false, nullable = true)
    @Where(clause = "CASE " +
                            "WHEN PartnerId != -1 AND AccountId = :accountId THEN PartnerId " +
                            "WHEN PartnerId = :accountId THEN AccountId " +
                            "ELSE :accountId " + 
                        "END")
    AccountData account;

账户类:

@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
int id;

@Column(name="FormattedName")
String formattedName;

在这里您可以看到我想使用“:accountId”发送一个 ID 作为参数进行查询,该参数将用于定义连接列。

这个问题:custom join clause 实际上做了类似的事情。这就是为什么我专注于 where 子句

补充:我还发现了一些符合条件的东西

Criteria criteria = session.createCriteria(InvoiceDesignData.class, "design");
            criteria.createCriteria("design.account", "acc", JoinType.LEFT_OUTER_JOIN, Restrictions.eqProperty("acc.id", "design.partnerId"));

            invoiceDesignList = criteria.list();

但这并没有忽略第一个条件,而是使用 AND 向 ON 子句添加了一个附加条件。我从@one-to-many 中删除了连接列,希望忽略第一个条件,但事实并非如此。产生的查询:

from InvoiceDesigns this_ left outer join UserAccount acc1_ on this_.account_id=acc1_.id and ( acc1_.id=this_.PartnerId )

提前致谢

【问题讨论】:

  • 请您说明您要达到的目标吗?从您最初的描述来看,听起来您有一个 InvoiceDesigns 表,它可以通过两列之一连接到 UserAccount 表 - partnerId 列或 accountId 列。您已经说过此查询有效。那你是说你想把accountId作为参数传入?为什么是这样?对于任何给定的 InvoiceDesigns 对象,肯定已经定义了加入其相关 UserAccount 的机制。
  • 我更新了我的问题。希望它更具描述性。

标签: sql hibernate hibernate-annotations


【解决方案1】:

你可以试试移动case语句:

SELECT  d.Description, d.AccountId, d.PartnerId, a.FormattedName 
FROM    (SELECT *, CASE 
                WHEN PartnerId != -1 AND AccountId = 1 THEN PartnerId
                WHEN PartnerId = 1 THEN AccountId 
                ELSE 1
            END AS SmartID
         FROM InvoiceDesigns) d 
        INNER JOIN UserAccount a
        ON a.id = d.SmartID
WHERE d.AccountId = 1 OR PartnerId = 1

编辑:这基本上让您可以直接使用内联查询进行连接,而无需使用条件 ON 语句。

【讨论】:

  • 我需要检查查询及其内部选择的成本,如果不多我会接受这个
【解决方案2】:

如果您只想通过单个联接将每个设计映射到单个 AccountData 对象,但您希望根据其值加入 accountId 或 partnerId,那么您应该能够通过使用联接来做到这一点公式。你会想要这样的东西:

@ManyToOne
@JoinColumnsOrFormulas(
    { @JoinColumnOrFormula(
        formula = @JoinFormula(
         value = "case " +
                 "when partnerId != -1 and accountId = 1 then partnerId" +
                 "when partnerId = accountId then accountId " +
                 "else 1" +
                 "end", 
         referencedColumnName="id")) }
)

请注意,您需要使用@ManyToOne 注释,即使这实际上是一对一关联。如果您尝试一对一地使用连接公式,它将不起作用。

然后您可以使用普通的 HQL 连接简单地检索数据:

SELECT d.description, d.accountId, d.partnerId, a.formattedName FROM Design d 
inner join d.account a

【讨论】:

  • 这种方法的问题是我将有 2 个连接,而我只能用 1 个连接。这是一个非常繁忙的数据库,我必须尽可能降低查询成本
  • 我已经更改了答案,向您展示如何使用包含 case 语句的公式映射连接,因此它只会执行单个连接
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-23
  • 1970-01-01
  • 1970-01-01
  • 2021-04-30
  • 1970-01-01
相关资源
最近更新 更多