对单个 table 策略使用鉴别器值时,第一个插入的实体的鉴别器值为空,但该值在数据库中

When using discriminator value for single table strategy, the first inserted entity's discriminator value is null but the value is there in database

当inheritance/single table 策略使用鉴别器值时,第一个插入实体的鉴别器值为空,但该值在数据库中。 我必须重新启动服务器,以便查询结果包含鉴别器值:

package entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.MappedSuperclass;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;


@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="user_type", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorValue("Null")
@Table(name="ALLUSER")
@NamedQueries({
    @NamedQuery(name = "User.findAll", query = "SELECT u FROM User u"),
    @NamedQuery(name = "User.findByAccount", query = "SELECT u FROM User u WHERE u.account = :account")
})
public class User implements Serializable{
    
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String account;
    private String password;
    private String userType;
    
    public User() {
        super();
    }
    public User(String account, String password) {
        super();
        this.account = account;
        this.password = password;
    }
    
    @Id
    @Column(name = "account")
    public String getAccount() {
        return account;
    }
    public void setAccount(String account) {
        this.account = account;
    }
    
    @Column(name = "password")
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
    @Column(name = "user_type", insertable = false, updatable = false, nullable = false)
    public String getUserType() {
        return userType;
    }
    public void setUserType(String userType) {
        this.userType = userType;
    }
    
    @Override
    public String toString() {
        return account;
    }
    
    

}
@Entity
@DiscriminatorValue("Normal")
@NamedQueries({
    @NamedQuery(name = "NormalUser.findAll", query = "SELECT u FROM NormalUser u")
})
public class NormalUser extends User implements Serializable{
    
    /**
     * 
     */
    //private String account;
    private static final long serialVersionUID = 1L;
    private LinkedHashSet<Customer> customers;
    
    public NormalUser() {
        super();
    }
    

    @OneToMany(fetch=FetchType.EAGER, mappedBy="normalUser", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}) //eager can be optimized when deleting a normal user
    public LinkedHashSet<Customer> getCustomers() {
        return customers;
    }

    public void setCustomers(LinkedHashSet<Customer> customers) {
        this.customers = customers;
    }
    
//  @Column(name = "account")
//  //have to override in order to get account to use
//  public String getAccount() {
//      return account;
//  }
//  
//  public void setAccount(String account) {
//      this.account = account;
//  }
}

如果我只是添加一个新的普通用户(子实体),那么查询这个用户类型为空的用户:

我使用 eclipse-link 作为 JPA 实现和 Java EE 三层 Web 架构。 我知道这肯定与实体管理器的工作和持久性有关,但我不知道细节。我也不知道怎么解决。欢迎任何建议!

您没有在您的实体中设置 'type' 字段,并且 JPA 不会为您设置它 - 无论如何都不会在 java 对象中设置。如果在持久化实体时未设置它,则只要该实体被缓存(本地或共享 EMF 级缓存),它就会保持未设置状态。重新启动应用程序是有效的,因为它会清除缓存,强制从数据库中加载现有实体的任何提取,其中类型是根据鉴别器列值设置的。

您可以在创建class时设置类型,或者通过在实例上调用em.refresh强制从数据库重新加载数据。但是,在这种情况下,将类型列映射为基本映射似乎很奇怪 - getType 方法应该只是 return class 的静态鉴别器值,并且无论如何都不能更改类型字符串.