Динамическое предложение joincolumn и join с переменными
У меня есть однонаправленное отношение один к одному. то, чего я хочу достичь, это либо
- создайте предложение объединения с использованием CASE и отправьте в него переменные, чтобы я мог изменить столбец объединения (любые другие предложения по изменению столбца объединения также приветствуются)
- игнорируйте первое предложение, созданное hibernate, и создайте конкретное предложение ON, используя критерии, как показано в нижней части вопроса.
Мой запрос, который работает в SQL Manager:
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 Manager, а не в спящем режиме. это то, чего я хочу достичь, я хочу, чтобы Hibernate создал такой запрос.
Когда учетная запись, скажем, ID = 1, чтобы придерживаться примера, отображает проекты, которые они увидят
A) PartnerId дизайна НЕ равен -1, а AccountId равен 1, что означает, что он создан партнером для этой учетной записи и будет отображать formattedName партнера.
Это для обычных аккаунтов при просмотре доступных дизайнов. Если партнер создал для них дизайн, он увидит имя этого партнера.
B) PartnerId равен идентификатору учетной записи, что означает, что это партнерский дизайн, и будет отображаться 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;
Здесь вы можете видеть, что я хочу отправить ID для запроса в качестве параметра, используя ":accountId", который будет использоваться для определения столбца соединения.
этот вопрос: пользовательское предложение на самом деле делает нечто подобное. Вот почему я сосредоточился на пункте где
Дополнение: я тоже нашел что-то с критериями
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();
Но это не игнорирует первое условие и добавляет дополнительное условие к предложению ON, используя AND. Я удалил столбцы соединения из @one-to-many, надеясь проигнорировать первое условие, но это не так. Произведенный запрос:
from InvoiceDesigns this_ left outer join UserAccount acc1_ on this_.account_id=acc1_.id and ( acc1_.id=this_.PartnerId )
заранее спасибо
2 ответа
Вы можете попробовать переместить оператор 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.
Если вы хотите сопоставить каждый дизайн только одному объекту 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