具有实体管理器的JPA实体图getResultList()方法返回resopnse中任何类型的实体列表

时间:2018-06-06 11:57:58

标签: java hibernate jpa

Father.java

@Entity
@Table(name = ClinicManagementVariableUtils.TABLE_NAME_FOR_FATHER)
@JsonInclude(Include.NON_EMPTY)

@NamedQueries({ 
        @NamedQuery(name = "father.findAll", query = "SELECT f FROM Father f") 
})

@NamedEntityGraphs({
    @NamedEntityGraph(
        name = "graph.father.setOfChildrens", 
        attributeNodes = @NamedAttributeNode(value = "setOfChildrens")),
    })
})
public class Father {

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "fatherId", nullable = false, insertable = false, updatable = false)
    private String id;

    @Column(name = "name", columnDefinition = "varchar(50)")
    private String name;

    @Column(name = "firstName", columnDefinition = "varchar(50)")
    private String firstName;

    @Column(name = "lastName", columnDefinition = "varchar(50)")
    private String lastName;

    @Column(name = "degree", columnDefinition = "varchar(50)")
    private String degree;

    @OneToOne(mappedBy = "father")
    @JsonIgnore
    private Mother mother;

    @OneToMany(mappedBy = "father") // children
    private Set<Children> setOfChildrens;

    getter()
    setter()
}

Children.java

@Entity
@Table(name = ClinicManagementVariableUtils.TABLE_NAME_FOR_CHILDREN)
@JsonInclude(Include.NON_EMPTY)
public class Children {

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "childrenId", nullable = false, insertable = false, updatable = false)
    private String id;

    @Column(name = "name", columnDefinition = "varchar(50)", nullable = false)
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JsonIgnore
    private Father father;

    getter()
    setter()
}

Mother.java

@Entity
@Table(name = ClinicManagementVariableUtils.TABLE_NAME_FOR_MOTHER)
@JsonInclude(Include.NON_EMPTY)
public class Mother {

    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    @Column(name = "motherId", nullable = false, insertable = false, updatable = false)
    private String id;

    @Column(name = "name", columnDefinition = "varchar(50)", nullable = false)
    private String name;

    @OneToOne
    @JoinColumn(name = "fatherId")
    private Father father;

    getter()
    setter()
}

FatherDao.java

public interface FatherDao extends GenericModelDao<Father> {

    // Note : Return type is Mother instead of Father
    public List<Mother> getFathersUsingNativeQueryAndEntityGraph();
}

FatherDaoImpl.java

@Named
public class FatherDaoImpl extends GenericModelDaoImpl<Father> implements FatherDao {

    @PersistenceContext
    EntityManager entityManager;

    @Override
    public List<Mother> getFathersUsingNativeQueryAndEntityGraph() {
        EntityGraph graph = entityManager.getEntityGraph("graph.father.setOfChilrensAndAddresses");

        List<Mother> list = entityManager.createNamedQuery("father.findAll").setHint("javax.persistence.fetchgraph", graph)
                .getResultList();

        return list;
    }
}

FatherService.java

public interface FatherService {

    // Note : Return type is Mother instead of Father
    public List<Mother> getFathersUsingNativeQueryAndEntityGraph();
}

FatherServiceImpl.java

@Named
public class FatherServiceImpl implements FatherService {

    @Inject
    private FatherDao fatherDao;

    @Override
    public List<Mother> getFathersUsingNativeQueryAndEntityGraph() {
        return fatherDao.getFathersUsingNativeQueryAndEntityGraph();
    }

}

FatherController.java

@Controller
public class FatherController {

    private static final Logger LOGGER = LoggerFactory.getLogger(FatherController.class);

    @CrossOrigin
    @RequestMapping(value = "/getFathersUsingNativeQueryAndEntityGraph", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public List<Mother> getFathersUsingNativeQueryAndEntityGraph() {
        List<Mother> list = new ArrayList<>();
        try {
            // Note : now list of father object is return as list of mother but it working..
            list =  fatherService.getFathersUsingNativeQueryAndEntityGraph();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return list;
    }
}

Father.java中,有两种注释:

  • 原生查询
  • 实体图

现在在DAO层中,我使用getFathersUsingNativeQueryAndEntityGraph()方法中的图形查询执行本机查询,该方法将返回父亲列表。

但是当我在List<Mother>中抓取它时,即使Father.java中不存在这些字段,它也会返回Mother.java中的所有字段。

的疑问: 如果它返回Father.java的所有字段,那么它如何在Mother.java中返回响应?

1 个答案:

答案 0 :(得分:2)

<强> 1。由于您在任何地方都没有类型检查,因此该代码将始终进行编译。

<强> 2。只要您从未专门作为Mother对象访问该列表中的对象,您的代码就会运行。

如果在没有类参数的情况下使用createNamedQuery,则会创建一个无类型的Query对象,该对象会返回原始列表以及JPA返回的任何对象。

在您的代码中,此列表将包含Father个对象,因为这就是您要求的内容。

List<Mother> list = ...是错误的,但你的编译器并不知道这一点。由于类型参数仅在编译时检查,因此此代码将运行,并且在运行时 list期间将是包含Father个对象的通用列表。

这里你应该得到一个编译器警告关于将该通用列表转换为List<Mother>,因为编译器不能保证这是正确的。听取这样的警告,他们是有原因的。

只有当你这样做时:

Mother mother = list.get(0);

你会得到运行时错误,特别是ClassCastException。但是,您的编译器不会抱怨此,因为它认为您的列表将包含Mother个对象,因为您在上面撒谎。

修复您的代码

您应该使用TypedQuery代替,将您期望的课程传递给createNamedQuery

entityManager.createNamedQuery("father.findAll", Father.class)

这将在编译时期间强制执行正确的类型,因此执行List<Mother> list = ...将不再编译。