加入 table 列。怎么可能?

Join table with column. How is possible?

任何了解此类查询的人:

@Entity
@Table(name="ACCOUNT")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@NamedQueries({
  @NamedQuery(name = Account.GET_EXPIRATION_DATE, query="SELECT account.expirationDate FROM " +
        "Domain domain JOIN domain.account WHERE domain.id = :domainId"),
  @NamedQuery(name = Account.GET_BALANCE, query="SELECT account.balance FROM " +
  "Domain domain JOIN domain.account WHERE domain.id = :domainId")
})

我不明白这是什么 "Domain domain JOIN domain.account" 我们可以将一个 table 与另一个连接,但它接缝我们将 table 与列 .. 连接起来?

这些是相关的 类:

package com.smsoffice.admin;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;


import static javax.persistence.CascadeType.*;

import com.smsoffice.billing.Account;
import com.smsoffice.billing.PrepaidAccount;


@Entity
@Table(name="DOMAIN")
@NamedQueries({
  @NamedQuery(name=Domain.GET_ALL_DOMAINS, query="SELECT d FROM Domain d ORDER BY d.name"),
  @NamedQuery(name=Domain.GET_ACCOUNT, query="SELECT d.account FROM Domain d WHERE d.id = :id"),
  @NamedQuery(name=Domain.GET_DOMAIN_BY_STATUS, query="SELECT d FROM Domain d WHERE d.enabled = :enabled ORDER BY d.name"),
  @NamedQuery(name=Domain.GET_DOMAIN_BY_NAME, query="SELECT d FROM Domain d WHERE d.name = :name")
})
public class Domain implements Serializable {

  private static final long serialVersionUID = 1L;

  public final static String GET_ALL_DOMAINS = "Domain.getAllDomains";
  public final static String GET_ACCOUNT = "Domain.getAccount";

  public final static String GET_DOMAIN_BY_STATUS = "Domain.getAllDomainsByStatus";
  public final static String GET_DOMAIN_BY_NAME = "Domain.getDomainByName";

  public final static transient Domain ROOT = new Domain("ROOT");

  public static Domain SYSTEM_DOMAIN = new Domain("SYSTEM");

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private int id;

  @Column(unique = true, length = 96)
  private String name;

  //unique id of the service - one per domain
  @GeneratedValue(strategy = GenerationType.AUTO)
  private int serviceId;

  //indicates whether the domain is enabled
  private Boolean enabled = true;

  //short code for the domain sms events
  private int shortCode;

  //prefix for parsing 
  private String prefix;

  private String clientPrefix = "";

  //bank account
  @OneToOne(cascade = {PERSIST, REFRESH, REMOVE})
  private Account account = new PrepaidAccount();

  @OneToMany
  private Set<User> users = new HashSet<User>();

  public Domain() {}

  public Domain(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getServiceId() {
    return serviceId;
  }

  public void setServiceId(int serviceId) {
    this.serviceId = serviceId;
  }

  public int getShortCode() {
    return shortCode;
  }

  public void setShortCode(int shortCode) {
    this.shortCode = shortCode;
  }

  public String getPrefix() {
    return prefix;
  }

  public void setPrefix(String prefix) {
    this.prefix = prefix;
  }

  public Account getAccount() {
    return account;
  }

  public void setAccount(Account account) {
    this.account = account;
  }

  public Set<User> getUsers() {
    return users;
  }

  public boolean isEnabled() {
    return enabled;
  }

  public void setEnabled(boolean enabled) {
    this.enabled = enabled;
  }

  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }

    if (!(obj instanceof Domain)) {
      return false;
    }

    Domain domain = (Domain) obj;

    return getName().toUpperCase().equals(domain.getName().toUpperCase()); 
  }

  @Override
  public int hashCode() {
      return getName().toUpperCase().hashCode();
  }

  @Override
  public String toString() {
      return "[" + name + "("+ account + ")]";
  }

  public int getId() {
    return id;
  }

  public void setClientPrefix(String clientPrefix) {
    this.clientPrefix = clientPrefix != null ? clientPrefix : "";
  }

  public String getClientPrefix() {
    return clientPrefix;
  }
}

还有这个:

package com.smsoffice.billing;

import static javax.persistence.CascadeType.ALL;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Calendar;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.Table;


@Entity
@Table(name="ACCOUNT")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@NamedQueries({
  @NamedQuery(name = Account.GET_EXPIRATION_DATE, query="SELECT account.expirationDate FROM " +
        "Domain domain JOIN domain.account account WHERE domain.id = :domainId"),
  @NamedQuery(name = Account.GET_BALANCE, query="SELECT account.balance FROM " +
  "Domain domain JOIN domain.account account WHERE domain.id = :domainId")
})      
public abstract class Account {

  public static final MathContext MATH_CONTEXT = new MathContext(9, RoundingMode.HALF_UP);
  public static final int SCALE = 3;
  public static final int PRECISION = 9;

  public static final String GET_BALANCE = "Account.getBalance";

  public static final String GET_EXPIRATION_DATE = "Account.getExpirationDate";

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private int id;

  @Column(precision = PRECISION, scale = SCALE)
  protected BigDecimal balance = BigDecimal.ZERO;

  @OneToOne(cascade = ALL)
  protected Tariff tariff;

  private Date activationDate = new Date();

  private Date expirationDate;

  public Account() {
    Calendar calendar = Calendar.getInstance();
    calendar.add(Calendar.MONTH, 1);
    setExpirationDate(calendar.getTime());
  }

  public BigDecimal getBalance() {
    return balance;
  }

  public Tariff getTariff() {
    return tariff;
  }

  public void setTariff(Tariff tariff) {
      this.tariff = tariff;
  }

  void deposit(BigDecimal amount) {
    balance = balance.add(amount).setScale(SCALE, MATH_CONTEXT.getRoundingMode());
  }

  abstract boolean hasCredit(int eventCount);

  abstract void makePayment(int eventCount) throws PaymentException;

  public int getId() {
    return id;
  }

  public Date getActivationDate() {
    return activationDate;
  }

  public void setActivationDate(Date activationDate) {
    this.activationDate = normalizeActivationDate(activationDate);
  }

  void setExpirationDate(Date expirationDate) {
    this.expirationDate = normalizeExpirationDate(expirationDate);
  }

  public Date getExpirationDate() {
    return expirationDate;
  }

  public boolean isExpired() {

    Date now = new Date();

    return now.after(expirationDate);
  }

  @Override
  public String toString() {
      return "[balance: " + balance + "; tariff: " + (tariff != null ? tariff.getPrice() : "no tariff") + "; expiration date: " + expirationDate.toString() + "]"; 
  }

  public void setBalance(BigDecimal newBalance) {
    this.balance = newBalance;
  }

  private static final Date normalizeActivationDate(Date date) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    return cal.getTime();
  }

  private static final Date normalizeExpirationDate(Date date) {

    Calendar cal = Calendar.getInstance();
    cal.setTime(date);

    cal.set(Calendar.HOUR_OF_DAY, 23);
    cal.set(Calendar.MINUTE, 59);
    cal.set(Calendar.SECOND, 59);    
    cal.set(Calendar.MILLISECOND, 0);
    return cal.getTime();
  }

}

好吧,这些并不是真正的 SQL 查询,而是 JPQL 查询 - 有一个很好的 tutorial 描述,以及非常好的示例。请注意,在 JPQL 中,您不直接使用 tables,而是使用域模型的实体。

但是对于你的问题,让我们以这个查询为例:

SELECT account.balance FROM Domain domain JOIN domain.account WHERE domain.id = :domainId
  • SELECT account.balance 将 return 加入给定域记录的帐户的 balance 属性值
  • FROM Domain domain 表示 Domain 实体将用于查询来自相关 table 的数据,在 Domain 实体上使用 @Table(name="DOMAIN") 定义;小写 domain 只是在此查询中使用的别名(参见例如查询的 WHERE 部分)
  • JOIN domain.account 将与 Domain 实体的 account 字段上定义的注解 @OneToOne(cascade = {PERSIST, REFRESH, REMOVE}) 一起使用,从 [=54= 中获取相关记录]由Account个实体
  • 代表
  • WHERE domain.id = :domainId 会将结果限制为 return 只有 Domain 和给定的 id,以及它的 account:domainId 部分是 "query parameter" 并且很可能在代码中的某处用实际值替换,使用 query.setParameter("domainId", someValue);
  • 之类的代码

所以整个查询应该 return BigDecimal 类型的值(参见 Account 实体中定义的字段 balance)。