「org.hibernate.query.SemanticException: Could not resolve attribute 'owner_id' 」のエラー
データベースのカラム取得ができないエラーの解消をしたい
開発環境
- macOS Ventura Ver.13.5.1
- Eclipse IDE Ver.4.29
- Eclipse2023 Pleiades All in One
- STS Ver.4.20
- sprig boot 3.1.2
- Java Ver.21
状況
現在、Todoアプリ開発を通してJava言語学習に取り組んでいます。
機能としては、
- ログイン機能(エラー)+検索機能
- TodoリストのCRUD処理(動作問題なし)
となっています。
Todoリストの機能を実施後、
「ユーザーのログイン機能とログインユーザー毎にアクセスできるTodoを制限しようとした」タイミングでエラーとなりました。
発生している問題・エラー
org.hibernate.query.SemanticException: Could not resolve attribute 'owner_id' of 'com.example.todolist.entity.Todo'
直接原因)
Caused by: org.hibernate.query.SemanticException: Could not resolve attribute 'owner_id' of 'com.example.todolist.entity.Todo'
上記エラー文より、Entityクラスの「owner_id」が解決できないと記載。
下記はEntityクラスとそのメタクラスになる。
Entity.Todo.java
package com.example.todolist.entity;
import java.sql.Date;
import java.util.ArrayList;
import java.util.List;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OrderBy;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.ToString;
//エンティティクラスと宣言
@Entity
//対応するテーブルを設定
@Table(name = "todo")
@Data
//9/12追加
@ToString(exclude = "taskList") //@Dataの自動生成のtoStringから除外しないとtaskListは自分でオブジェクトを保持するのでStackOverFlowとなる。
public class Todo {
//Todoのデータベースのカラム、IDは主キーであると表す。
@Id
//主キーに自動で番号を割り振ることを宣言。「GenerationType」の方式を採用している。
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "title")
private String title;
@Column(name = "importance")
private Integer importance;
@Column(name = "urgency")
private Integer urgency;
@Column(name = "deadline")
private Date deadline;
@Column(name = "done")
private String done;
//ユーザーごとにTodoを分けるために追加(9/27)
@Column(name = "owner_id")
private Integer ownerId;
//9/12taskテーブル追加による追加
@OneToMany(mappedBy = "todo", cascade = CascadeType.ALL) //1側であることを表す。Task.javaのManyToOneのプロパティと同期している。
//cascadeは登録、削除、更新といった処理を両方ともに適用させる
@OrderBy("id asc") //テーブル更新時に自動で並び順が変更されるため、idで昇順になるように設定。
private List<Task> taskList = new ArrayList<>();
//Todoへの参照設定
public void addTask(Task task) {
task.setTodo(this);
taskList.add(task);
}
}
Entity.Todo_.java
package com.example.todolist.entity;
import java.sql.Date;
import jakarta.annotation.Generated;
import jakarta.persistence.metamodel.SingularAttribute;
import jakarta.persistence.metamodel.StaticMetamodel;
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(Todo.class)
public abstract class Todo_ {
public static volatile SingularAttribute<Todo, Integer> urgency;
public static volatile SingularAttribute<Todo, Integer> importance;
public static volatile SingularAttribute<Todo, Integer> id;
public static volatile SingularAttribute<Todo, Integer> owner_id;
public static volatile SingularAttribute<Todo, String> title;
public static volatile SingularAttribute<Todo, Date> deadline;
public static volatile SingularAttribute<Todo, String> done;
public static final String URGENCY = "urgency";
public static final String IMPORTANCE = "importance";
public static final String ID = "id";
public static final String OWNER_ID = "owner_id";
public static final String TITLE = "title";
public static final String DEADLINE = "deadline";
public static final String DONE = "done";
}
検索メソッド(Criteria APIを利用)の引数のaccountIdが「owner_id」の値を取得できていない。
Dao.TodoDaoImpl.java
package com.example.todolist.dao;
import java.util.ArrayList;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import com.example.todolist.common.Utils;
import com.example.todolist.entity.Todo;
import com.example.todolist.entity.Todo_;
import com.example.todolist.form.TodoQuery;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class TodoDaoImpl implements TodoDao {
private final EntityManager entityManager;
// //Criteria APIによる検索
@Override
public Page<Todo> findByCriteria(TodoQuery todoQuery, Integer accountId,
Pageable pageable) {
// TODO 自動生成されたメソッド・スタブ
//9/7追記
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Todo> query = builder.createQuery(Todo.class);
Root<Todo> root = query.from(Todo.class);
List<Predicate> predicates = new ArrayList<>();
//件名
String title = "";
if (todoQuery.getTitle().length() > 0) {
title = "%" + todoQuery.getTitle() + "%";
} else {
title = "%";
}
predicates.add(builder.like(root.get(Todo_.TITLE), title));
//重要度
if (todoQuery.getImportance() != -1) {
predicates.add(
builder.and(builder.and(builder.equal(root.get(Todo_.IMPORTANCE), todoQuery.getImportance()))));
}
//緊急度
if (todoQuery.getUrgency() != -1) {
predicates.add(builder.and(builder.and(builder.equal(root.get(Todo_.URGENCY), todoQuery.getUrgency()))));
}
//期限:開始〜
if (!todoQuery.getDeadlineFrom().equals("")) {
predicates.add(builder.and(builder.and(builder.greaterThanOrEqualTo(root.get(Todo_.DEADLINE),
Utils.str2date(todoQuery.getDeadlineFrom())))));
}
//〜期限:終了
if (!todoQuery.getDeadlineTo().equals("")) {
predicates.add(builder.and(builder.and(builder.lessThanOrEqualTo(root.get(Todo_.DEADLINE),
Utils.str2date(todoQuery.getDeadlineTo())))));
}
//完了
if (todoQuery.getDone() != null && todoQuery.getDone().equals("Y")) {
predicates.add(builder.and(builder.and(builder.equal(root.get(Todo_.DONE), todoQuery.getDone()))));
}
// 所有者
predicates.add(
builder.and(builder.equal(root.get(Todo_.OWNER_ID), accountId)));// accountId(session) =OWNER_ID(Todoテーブル)の条件のみを追加。
//SELECT作成
Predicate[] predArray = new Predicate[predicates.size()];
predicates.toArray(predArray);
query = query.select(root).where(predArray).orderBy(builder.asc(root.get(Todo_.id)));
//クエリ生成
TypedQuery<Todo> typedQuery = entityManager.createQuery(query);
//該当レコード数取得
int totalRows = typedQuery.getResultList().size();
// 先頭レコードの位置設定
typedQuery.setFirstResult(pageable.getPageNumber() * pageable.getPageSize()); //
//1ページあたりの件数
typedQuery.setMaxResults(pageable.getPageSize());
// //検索
// List<Todo> list = entityManager.createQuery(query).getResultList();
Page<Todo> page = new PageImpl<Todo>(typedQuery.getResultList(), pageable, totalRows); //
return page;
}
}
データベースの関係
account:todo 1対多
todo:task 1対多
自分で試したこと
「owner_id」がテーブルの1対多の主キーとして設定できていないのかと考えるもどのようにしたら良いかわからず。
Entity.Account.java
package com.example.todolist.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Table(name = "account")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "login_id")
private String loginId;
@Column(name = "name")
private String name;
@Column(name = "password")
private String password;
}
0 likes