JPA Entity Graph с менеджером сущностей getResultList () возвращает ответ сущности любого типа в ответе - PullRequest
0 голосов
/ 06 июня 2018

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;
    }
}

In Father.java существует 2 типа аннотаций:

  • Собственный запрос
  • Граф сущностей

Теперь на уровне DAO я выполняю собственный запрос с запросом графа вgetFathersUsingNativeQueryAndEntityGraph() метод, который возвращает список отцов.

Но когда я получаю его в List<Mother>, он также возвращает все поля из Father.java, даже если эти поля не существуют в Mother.java.

Сомнение: если он возвращает все поля Father.java, то как возможно, что он возвращает ответ в Mother.java?

1 Ответ

0 голосов
/ 06 июня 2018

1.Поскольку у вас нет проверок типов, этот код всегда будет компилироваться.

2.До тех пор, пока вы никогда не получите доступ к объекту в этом списке, в частности к объекту Mother, ваш код будет выполняться.

Когда вы используете createNamedQuery без параметра класса, вы создаете нетипизированный Query object, который возвращает необработанный список с любыми объектами, которые возвращает JPA.

В вашем коде этот список будет содержать Father объектов, потому что это то, что вы просили.

Запись List<Mother> list = ... неверна, но ваш компилятор этого не знает.Поскольку параметр type проверяется только во время компиляции , этот код будет выполняться, и во время runtime list будет общий список, содержащий Father объектов.

Вы должны получить здесь компилятор предупреждение о преобразовании этого общего списка в List<Mother>, потому что компилятор не может гарантировать, что это правильно.Слушайте такие предупреждения, они есть по какой-то причине.

Только когда вы сделаете это:

Mother mother = list.get(0);

вы получите ошибку времени выполнения , в частности ClassCastException.Однако ваш компилятор не будет жаловаться на это , потому что считает, что ваш список будет содержать Mother объектов, потому что вы соврали ему выше.

Исправьте ваш код

Вместо этого вы должны использовать TypedQuery, передав ожидаемый класс createNamedQuery:

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

Это приведет к правильному типу во время времени компиляции так что List<Mother> list = ... больше не будет компилироваться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...